BBSDEV.DRP is a line-oriented drop file for passing a BBS session to a
door. It keeps the simple, positional interface used by traditional BBS drop
files while defining the character encoding, data types, time representation,
and extension rules that older formats leave ambiguous.
This document specifies format version 1.0. The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY are to be interpreted as described by BCP 14.
The canonical file name is BBSDEV.DRP.
The BBS MUST create a separate file for each active node and MUST completely write and close it before starting the door. The BBS MUST restrict access to the BBS and door processes and MUST remove the file after the door exits. Per-node directories are RECOMMENDED.
Before starting the door, the BBS MUST set the environment variable
BBSDEV_DRP in the door's environment. Its value is the full absolute path,
including the BBSDEV.DRP file name, of the drop file for this invocation. For
example:
/var/lib/example-bbs/node1/BBSDEV.DRP
C:\BBS\NODE1\BBSDEV.DRP
The value contains only the path: it is not surrounded by quotation marks, even when the path contains spaces, and it contains no command-line escaping. The door MUST read it directly from its environment rather than parse it through a command shell. Environment-variable names are case-sensitive on platforms that distinguish case, so the uppercase spelling is REQUIRED.
The variable uses the operating system's native path syntax and environment
encoding; it is not governed by the drop file's UTF-8 representation or by the
terminal encoding on line 12. On Windows, producers and consumers SHOULD use
the Unicode environment and pathname APIs. A door MAY also accept an explicit
path through its own command-line or configuration interface, but
BBSDEV_DRP is the standard discovery mechanism.
The file is read-only input to the door. A door MUST NOT use it to return user or session changes to the BBS. Producers MUST NOT put passwords, authentication tokens, or other secrets in it.
A producer MUST:
- encode the file as UTF-8 without a byte-order mark;
- end every line, including the last, with CRLF;
- write exactly 19 lines for version 1.0;
- write no NUL, C0/C1 control, or DEL characters in a field; and
- write no leading or trailing Unicode whitespace in a field value.
A consumer MUST accept CRLF. For interoperability with Unix tools, it MUST also accept LF. It MUST reject bare CR line endings, invalid UTF-8, a UTF-8 byte-order mark, missing required lines, and invalid field values. There is no quoting or escaping mechanism; a value cannot contain a line ending.
Except for the three cases explicitly identified below, empty fields are invalid:
- line 3 is empty for
localandstdio; and - line 10 is empty when no CTerm revision was detected; and
- line 11 is empty when the BBS imposes no forced logoff time.
Line 12 describes the encoding of terminal data exchanged with the caller. It
does not change the UTF-8 encoding of BBSDEV.DRP itself.
| Line | Field | Required representation |
|---|---|---|
| 1 | Format version | 1.0 |
| 2 | Communications type | A token from the communications registry below |
| 3 | Communications parameters | The positional value required by line 2 |
| 4 | User alias | Non-empty UTF-8 text |
| 5 | Unique user key | Non-empty opaque UTF-8 text |
| 6 | Screen width | Decimal integer from 1 through 65535 |
| 7 | Screen height | Decimal integer from 1 through 65535 |
| 8 | ANSI | Uppercase Y or N |
| 9 | RIP | Uppercase Y or N |
| 10 | CTerm version | Dotted-decimal revision, or empty if unavailable |
| 11 | Time of logoff | UTC timestamp in YYYY-MM-DDTHH:MM:SSZ form, or empty for no forced logoff |
| 12 | Encoding | IANA-registered character-set name |
| 13 | Language | Well-formed BCP 47 language tag |
| 14 | BBS software name and version | Non-empty UTF-8 text |
| 15 | Board name | Non-empty UTF-8 text |
| 16 | Sysop alias | Non-empty UTF-8 text |
| 17 | Access level | Unsigned decimal integer, cosysop, or sysop |
| 18 | Node number | Unsigned decimal integer |
| 19 | Show local display | Uppercase Y or N |
The user key on line 5 is case-sensitive and opaque. A producer MUST keep it stable for the lifetime of the user account and MUST NOT assign it to another account on the same BBS. It is unique only within the BBS; consumers MUST NOT assume that it identifies the same person on another board. Consumers MUST NOT case-fold, parse, or Unicode-normalize it.
The software, board, and sysop values on lines 14 through 16 are display text. Their contents have no machine-readable substructure. In particular, a consumer MUST NOT try to split line 14 into separate product and version fields.
An unsigned access level is a BBS-defined ordinal with no portable authorization meaning. A consumer MAY interpret it when it has BBS-specific knowledge, but MUST NOT assume that equal numbers from different BBS packages grant equal privileges. Numeric access levels and node numbers range from 0 through 18446744073709551615.
Two lowercase access-level tokens have portable meanings:
sysopidentifies the board's system operator; andcosysopidentifies a user to whom the sysop has delegated system-operator responsibilities.
The named roles do not establish operating-system privileges, and a door MUST NOT treat possession of this file as authentication. They allow doors to recognize those roles without guessing a BBS package's numeric convention.
Width and height describe the terminal's usable character-cell area for the door. Status lines or other rows unavailable to the door are not included.
Lines 8 and 9 state whether ANSI and RIP respectively are enabled and available to this door session. They are independent flags.
Line 10 is the detected CTerm protocol revision, such as 1.332. It is not
the version of the SyncTERM application. A fork that reports additional CTerm
revision components retains them, for example 1.332.1. The field is empty if
the BBS did not detect CTerm support.
Line 12 MUST contain the Preferred MIME Name from the IANA character sets
registry when the entry has one, or the registered Name otherwise. Matching
is case-insensitive, but producers SHOULD use the registry's spelling. Examples
include UTF-8 and IBM437.
Line 13 MUST be a well-formed BCP 47 language tag. Language-tag comparison is
case-insensitive. Producers SHOULD use the casing recommended by BCP 47, such
as en-US.
N on line 19 requires a door that controls a separate operator-side display
to suppress that display. Y requests that display when the door supports it.
This field never disables the communications channel named on line 2 and has no
effect when no separate local display exists.
When non-empty, line 11 is an absolute UTC deadline using the Internet
date/time form from RFC 3339, restricted to whole seconds and an uppercase
Z. Numeric offsets, fractional seconds, and leap-second values are not
permitted. An empty line means this drop file imposes no forced logoff time.
When a deadline is present, the door MUST stop accepting interaction and exit when its current UTC time is equal to or later than the deadline. It SHOULD check the deadline during any potentially long operation, not only while waiting for input. The BBS SHOULD enforce the same deadline independently in case a door fails to do so. When line 11 is empty, the door MUST NOT invent a time limit from any other field in this format; the BBS MAY still end the door session externally.
Line 2 selects the door-facing I/O mechanism. It intentionally does not name the caller's original protocol. The BBS is responsible for any SSH, WebSocket, Telnet, or other transport processing necessary to provide the mechanism described here.
| Line 2 | Line 3 | Contract |
|---|---|---|
local |
Empty | The door uses its current local console. |
stdio |
Empty | Terminal input arrives on standard input and terminal output is written to standard output. Standard error is not caller output. |
socket |
Unsigned decimal native socket value | An inherited, connected, bidirectional socket carrying only terminal bytes. Transport framing and negotiation have been removed. |
serial |
Unsigned decimal file descriptor | An inherited, open, preconfigured POSIX serial descriptor used for both reading and writing. |
winserial |
Unsigned decimal handle | An inherited, open, preconfigured Win32 COM HANDLE used for both reading and writing. |
uart |
HHHH,I |
Direct DOS UART access. HHHH is the four-uppercase-hex-digit I/O base without 0x; I is decimal IRQ 0 through 15. |
fossil |
Decimal port 0 through 254 | An initialized FOSSIL interface. The value is the zero-based value placed in register DX; 0 selects COM1. |
Native descriptors, socket values, and handles have no fixed text width. Their values MUST fit the native unsigned descriptor or handle type of the launched door. The producer is responsible for making the object inheritable, arranging its inheritance, keeping the door's copy valid for the session, and selecting a mode the door supports.
socket is a clean terminal byte stream, not necessarily the caller's original
network socket. A BBS can satisfy the contract with a socket pair and a bridge.
A raw Telnet socket that can still carry IAC negotiation does not satisfy the
contract.
The BBS MUST configure serial framing and speed before launch. A door MUST use
the existing configuration; this format deliberately carries neither baud rate
nor data/parity/stop-bit settings. For fossil, port 255 is reserved by
FSC-0015 and is invalid in this format.
A consumer MUST reject an unknown or unsupported communications type. It MUST NOT guess a fallback mechanism or reinterpret line 3 as another type.
Line 1 is a decimal major.minor format version. Neither component has leading
zeroes. Version 1.0 has exactly the 19 lines in this document.
A later minor version MAY append fields after the fields defined by an earlier minor version, add registry values, or relax validation so that a representation which was previously invalid becomes valid. Examples of a relaxation include allowing an existing line to be empty or accepting an additional form of an existing value.
Minor-version changes MUST be monotonic: every file valid under an earlier minor version remains valid, with exactly the same meaning, under every later minor version of the same major. A minor version therefore MUST NOT remove or reorder existing lines, change the interpretation of a previously valid value, or make a previously valid file invalid. Any such change requires a new major version.
A consumer MUST accept supported minor versions of a supported major. When it encounters a newer minor version, it MUST NOT reject the file solely because the minor number is newer. It MUST parse the core it understands and ignore appended lines it does not understand. It MAY reject the file if a known line uses a newly permitted representation or registry value it does not understand, or if it does not support the selected communications mode.
A consumer MUST reject an unknown major version. Producers MUST NOT append private lines to a version 1.0 file; they must use a registered later minor version. A producer SHOULD write the earliest minor version that defines every representation and field it emits.
The companion ABNF grammar defines the byte-level structure
of the version 1 core. The files below examples/ are canonical version 1.0
examples for every registered communications mode.