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.
267 lines
10 KiB
Markdown
267 lines
10 KiB
Markdown
# Attribute registry
|
|
|
|
This document is the source of truth for attribute key names used
|
|
across all `fpc-msgbase` backends.
|
|
|
|
`TUniMessage` has only two areas:
|
|
|
|
```pascal
|
|
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:
|
|
|
|
```pascal
|
|
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/`](../../fpc-ftn-transport/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`](../../fpc-ftn-transport/) since the PKT
|
|
backend moved out of fpc-msgbase in 0.4.0.
|