Removes all PKT code from fpc-msgbase. The wire format and its
container concerns now live in the sibling fpc-ftn-transport
library (units tt.pkt.format, tt.pkt.reader, tt.pkt.writer,
tt.pkt.batch). Pair this commit with fpc-ftn-transport's
0.2.0 (commit 6bb71a6).
Why: the previous "reader here, writer there" split (briefly
landed in 0.3.5) baked in a coupling that didn't survive a
fresh look. The writer reached into fpc-msgbase for types,
the wire format lived in the wrong house, and consumers reading
fpc-msgbase saw "PKT support" that was actually only half-
support. Cleanest split: PKT is a wire format, both directions
belong with the wire-format-aware library; fpc-msgbase becomes
purely real message bases (Hudson / JAM / Squish / MSG /
PCBoard / EzyCom / GoldBase / Wildcat).
Also a cleaner separation-of-concerns story: a BBS that just
reads JAM/Squish never needs fpc-ftn-transport. A pure store-
and-forward node doing only ArcMail unbundle never depends on
storage formats. Each library = one concern.
Removed:
src/formats/ma.fmt.pkt.pas -> tt.pkt.format
src/formats/ma.fmt.pkt.uni.pas -> tt.pkt.reader
(TPktMessageBase -> TPktReader)
src/ma.batch.pas -> tt.pkt.batch
(TPacketBatch class name unchanged)
tests/test_batch.pas -> tests/test_pkt_writer.pas
(consolidated PKT tests)
examples/example_tosser.pas -> moves with the batch helper
Reduced in src/ma.types.pas:
- PacketRecord
- FlavourType / FlavourTypeSet / DateTimeArray
- FlagsToFido / FidoToFlags
- VersionNum (PKT-product-code stamping)
All moved to tt.pkt.format.
Kept in src/ma.types.pas:
- mbfPkt enum value (so tt.pkt.reader can register the backend
with the unified-API factory; consumers still use the
standard MessageBaseOpen(mbfPkt, ...) shape)
Migration for vendoring consumers:
before: after:
uses ma.fmt.pkt; uses tt.pkt.format;
uses ma.fmt.pkt.uni; uses tt.pkt.reader;
uses ma.batch; uses tt.pkt.batch;
(no writer surface) uses tt.pkt.writer;
TPktMessageBase TPktReader
TPktFile, TPktMessage, (unchanged class names)
TPktHeaderInfo, etc.
TPacketBatch (unchanged)
Docs sweep:
- README: PKT row called out as "moved to fpc-ftn-transport";
TPacketBatch removed from features.
- docs/architecture.md: layer diagram drops PKT + ma.batch;
new sibling-library box added for fpc-ftn-transport.
- docs/attributes-registry.md: PKT column dropped from per-
format support matrix; pointer to fpc-ftn-transport.
- docs/API.md: PKT cheat-sheet entry redirects to
fpc-ftn-transport; TPacketBatch section reduced to a
"moved" pointer with the new uses-clause shape.
- docs/ftsc-compliance.md: Type-2 / 2+ / 2.2 / AuxNet rows
annotated as living in tt.pkt.format.
Suite: 47/47 across 9 programs (was 9 with test_batch; now 9
with the PKT bits dropped from test_consumer_round1 and
test_hwm). All other tests untouched.
10 KiB
Attribute registry
This document is the source of truth for attribute key names used
across all fpc-msgbase backends.
TUniMessage has only two areas:
TUniMessage = record
Body: AnsiString; { only the message text }
Attributes: TMsgAttributes; { everything else, key/value }
end;
Every header field, kludge, control line, and per-format flag a
backend understands lives in Attributes under one of the keys
below. Backends drop keys they don't recognise on Write (RFC 822
X-header semantics). Callers can query base.SupportsAttribute(K)
before setting a key to know up-front which backends carry it.
Naming convention: lowercase, dot-namespaced. Universal /
FTSC-defined keys are unqualified (from, msgid). Format-
specific keys are prefixed with the format name (jam.msgidcrc,
squish.umsgid, pcb.confnum).
Tier 1 — Universal headers
Every Fido format sets these on Read; every backend reads them on Write. Equivalent to the always-present headers in any classic BBS message.
| Key | Type | Meaning |
|---|---|---|
msg.num |
int | Backend-assigned message number / index |
from |
string | Author name |
to |
string | Recipient name |
subject |
string | Message subject |
date.written |
date | When author wrote the message |
date.received |
date | When local system received |
addr.orig |
ftn | Originating FTN address (zone:net/node[.point]) |
addr.dest |
ftn | Destination FTN address |
area |
string | Echo area tag (echomail) |
board |
int | Conference / board number for multi-board formats |
cost |
int | Cost in cents (FTS-1 backends) |
Tier 2 — Canonical attribute bits
Boolean flags derived from the FTS-1 attribute word, plus extensions
some backends carry as separate bits. Always written via
SetBool(K, true); absent (or false) when not set.
| Key | FTS-1 | Meaning |
|---|---|---|
attr.private |
0x0001 | Private message |
attr.crash |
0x0002 | Crash priority |
attr.received |
0x0004 | Recipient has read |
attr.sent |
0x0008 | Sent to destination |
attr.fileattach |
0x0010 | File attached |
attr.intransit |
0x0020 | In transit |
attr.orphan |
0x0040 | No matching destination |
attr.killsent |
0x0080 | Kill after sending |
attr.local |
0x0100 | Originated locally |
attr.hold |
0x0200 | Hold for pickup |
attr.filereq |
0x0400 | File request |
attr.returnreceipt |
0x0800 | Return receipt requested |
attr.isreceipt |
0x1000 | This message is a receipt |
attr.auditreq |
0x2000 | Audit trail requested |
attr.fileupdreq |
0x4000 | File update request |
attr.deleted |
— | Tombstoned (per-base) |
attr.read |
— | Marked-read (per-user) |
attr.echo |
— | Echomail (vs netmail) |
attr.direct |
— | Direct flavour |
attr.immediate |
— | Immediate flavour |
attr.locked |
— | Locked (no edit) |
attr.netpending |
— | Pending netmail toss |
attr.echopending |
— | Pending echomail toss |
attr.nokill |
— | Protected from purge |
Tier 3 — FTSC kludges
Standard FTSC kludge lines, named after the kludge name without
the leading ^A. Multi-line attributes (SEEN-BY, PATH, Via) join
their lines with #13.
| Key | Type | Spec | Meaning |
|---|---|---|---|
msgid |
string | FTS-9 | Globally unique message ID |
replyid |
string | FTS-9 | Reply linkage to a previous MSGID |
pid |
string | FRL-1004 | Producer ID (creating tosser/editor) |
tid |
string | FSC-46 | Tosser ID |
flags |
string | FRL-1005 | Routing/handling flags |
chrs |
string | FTS-5003 | Character set declaration |
tzutc |
string | FTS-4001 | Time-zone offset from UTC |
seen-by |
multi-string | FTS-4 | SEEN-BY lines (one node-list per line) |
path |
multi-string | FTS-4 | PATH lines (one node-list per line) |
via |
multi-string | FTS-4009 | Via lines (one per relay) |
intl |
string | FSC-4008 | INTL kludge: <dest-zone:net/node> <orig-zone:net/node> for cross-zone netmail |
fmpt |
string | FSC-4008 | FMPT (origin point number) |
topt |
string | FSC-4008 | TOPT (destination point number) |
Unknown FTSC kludges
Any ^A<NAME>: <value> line whose <NAME> is not in the table
above is preserved as kludge.<lowername> regardless of which
backend stored it. Example: ^aXFOO: bar → kludge.xfoo =
'bar'.
This is the universal forward-compat slot for FTSC-form kludges
the library doesn't recognize natively. All four kludge-aware
backends (JAM, Squish, MSG, PKT) use the same kludge.*
namespace so a consumer can find passthrough kludges without
switching on format.
JAM's numeric SubField IDs that have no FTSC analogue stay
namespaced as jam.subfield.<id> (those aren't FTSC-form
kludges; they're JAM-specific binary subfields).
Multi-line attribute helpers
Attributes that store multiple lines (seen-by, path, via,
trace) join their lines with #13. Use the typed accessors
on TMsgAttributes to avoid manual splitting:
list := msg.Attributes.GetList('seen-by'); // TStringDynArray
msg.Attributes.SetList('path', list); // joins with #13
msg.Attributes.AppendListItem('seen-by', '3/777');
Tier 4 — Format-specific keys
These are namespaced and only meaningful to the format that produces them. Other backends ignore them on Write (silently dropped — fine).
JAM
| Key | Type | Meaning |
|---|---|---|
jam.msgidcrc |
int | Index fast-path CRC of MSGID |
jam.replycrc |
int | Index fast-path CRC of ReplyID |
jam.dateprocessed |
unix-int | Tosser timestamp |
jam.passwordcrc |
int | Per-message password CRC |
jam.cost |
int | JAM-level cost (separate from cost) |
jam.timesread |
int | Times-read counter |
jam.replyto |
int | Parent in reply chain |
jam.reply1st |
int | First child in reply chain |
jam.replynext |
int | Next sibling in reply chain |
jam.attribute2 |
int | Reserved JAM attribute2 word |
jam.subfield.<id> |
multi | Passthrough for JAM-numeric subfields with no FTSC kludge analogue |
(JAM's JAM_FTSKLUDGE subfields are parsed through the shared
kludge dispatcher, so their content lands in the canonical slot
— msgid, intl, etc., or kludge.<name> for unknowns —
rather than a JAM-specific bag.)
Squish
| Key | Type | Meaning |
|---|---|---|
squish.umsgid |
int | UMsgID (per-area unique number) |
squish.utcofs |
int | UTC offset in minutes |
squish.replyto |
int | Reply chain parent |
squish.kludge.<name> |
multi | Passthrough for unknown CtrlInfo kludges |
Hudson / GoldBase
| Key | Type | Meaning |
|---|---|---|
hudson.prevreply |
int | Previous message in reply chain |
hudson.nextreply |
int | Next message in reply chain |
hudson.timesread |
int | Times-read counter |
goldbase.prevreply |
int | (GoldBase variant) |
goldbase.nextreply |
int | (GoldBase variant) |
goldbase.timesread |
int | (GoldBase variant) |
EzyCom
| Key | Type | Meaning |
|---|---|---|
ezy.extattr |
int | EzyCom ExtAttr byte |
ezy.prevreply |
int | Reply chain prev |
ezy.nextreply |
int | Reply chain next |
PCBoard
| Key | Type | Meaning |
|---|---|---|
pcb.refnum |
int | RefNum field |
pcb.status |
int | Raw PCB status byte |
pcb.active |
int | Active flag |
pcb.echo |
int | Echo flag |
pcb.export |
int | Export flag |
pcb.extra2 |
int | Extra2 byte (incl. Allfix-sent bit 6) |
pcb.extra3 |
int | Extra3 byte |
pcb.hastags |
int | HasTags flag |
pcb.origin |
int | Origin flag |
pcb.readnum |
int | ReadNum word |
pcb.extendedstatus |
int | Extended status byte |
pcb.password |
string | Per-message password (max 12 chars) |
Wildcat
| Key | Type | Meaning |
|---|---|---|
wildcat.confnum |
int | Conference number this message lives in |
wildcat.mflags |
int | Raw mFlags word from TMsgHeader |
PKT
PKT-format attributes (pkt.cost etc.) live in fpc-ftn-transport's
docs/ since the PKT backend
moved out of fpc-msgbase in 0.4.0. Unknown FTSC kludges still
follow the universal kludge.<lowername> convention regardless
of which library produced them.
MSG (FTS-1)
| Key | Type | Meaning |
|---|---|---|
msg.replyto |
int | Reply chain parent |
msg.nextreply |
int | Reply chain next |
msg.timesread |
int | Times-read counter |
msg.kludge.<name> |
multi | Passthrough for unknown body kludges |
Per-format support matrix
X = the backend's ClassSupportedAttributes lists the key.
Blank = backend has no slot for it; setting the key has no effect
on Write, and the key won't appear in Attributes after a Read.
| Key | JAM | Squish | MSG | Hudson | GoldBase | EzyCom | PCB | WC |
|---|---|---|---|---|---|---|---|---|
msg.num |
X | X | X | X | X | X | X | X |
from / to / subject |
X | X | X | X | X | X | X | X |
addr.orig / addr.dest |
X | X | X | X | X | X | X | X |
date.written |
X | X | X | X | X | X | X | X |
date.received |
X | X | X | X | ||||
area |
X | X | X | X | X | X | X | X |
board |
X | X | X | |||||
cost |
X | X | X | X | X | |||
attr.private |
X | X | X | X | X | X | X | X |
attr.crash |
X | X | X | X | X | X | ||
attr.received |
X | X | X | X | X | X | X | |
attr.sent |
X | X | X | X | X | X | X | |
attr.killsent |
X | X | X | X | X | X | ||
attr.local |
X | X | X | X | X | X | X | |
attr.hold |
X | X | X | X | X | |||
attr.fileattach |
X | X | X | X | X | X | ||
attr.returnreceipt |
X | X | X | X | X | |||
attr.deleted |
X | X | X | X | X | X | X | |
msgid |
X | X | X | |||||
replyid |
X | X | X | |||||
pid |
X | X | X | |||||
flags |
X | X | X | |||||
seen-by |
X | X | X | |||||
path |
X | X | X | |||||
Format-specific (<fmt>.*) |
X | X | X | X | X | X | X | X |
(Always check at runtime via SupportsAttribute(K) rather than
relying on this table — it can drift. The capability list each
backend ships in ClassSupportedAttributes is authoritative.)
PKT's column lives in
fpc-ftn-transport since the PKT
backend moved out of fpc-msgbase in 0.4.0.