Files
fpc-msgbase/docs/attributes-registry.md
Ken Johnson 1e253e8a78 Phase 5: attribute registry + arch / proposal / README updates
New docs/attributes-registry.md publishes the canonical attribute
key catalog in four tiers:

  1. Universal headers — msg.num, from, to, subject, date.*, addr.*,
     area, board, cost.  Every Fido format carries them.
  2. Canonical attribute bits — attr.private, attr.crash, etc.,
     mapped to/from the FTS-1 attribute word.
  3. FTSC kludges — msgid, replyid, pid, tid, flags, chrs, tzutc,
     seen-by, path, via.  Multi-line keys use #13 between lines.
  4. Format-specific — jam.*, squish.*, hudson.*, goldbase.*, ezy.*,
     pcb.*, wildcat.*, pkt.*, msg.*.  Each backend's namespace.

Plus a per-format support matrix showing which keys each backend
carries. Authoritative source remains each backend's
ClassSupportedAttributes -- the matrix can drift; SupportsAttribute()
is the runtime-correct query.

docs/architecture.md TUniMessage section rewritten:
- Documents the strict two-area model (Body + Attributes only).
- Body holds only the message text, never kludges or headers.
- Library never composes presentation -- consumers walk Attributes
  and assemble their own display.
- Adds the capabilities API section pointing at the registry.
- Removes the stale "kludge lines intact and CR-separated" promise
  the previous adapter implementations didn't honor.

docs/PROPOSAL.md flags the original Extras-bag section as
SUPERSEDED 2026-04-17, points to the registry + architecture docs
as the live design. Original text retained as historical context
since it captures the conversation that drove the redesign.

README.md:
- Features list now leads with the lossless two-area model and the
  capabilities API.
- Adds a Status note flagging 0.2 as a breaking change vs 0.1 with
  a one-paragraph migration sketch (msg.WhoFrom -> Attributes.Get
  ('from'), etc.).
- Documentation index links to the new registry doc.
2026-04-17 14:35:19 -07:00

8.6 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)

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.ftskludge multi Passthrough for JAM_FTSKLUDGE subfields
jam.subfield.<id> multi Passthrough for unknown subfield IDs

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

Key Type Meaning
pkt.cost int Packet-level cost (separate from cost)
pkt.kludge.<name> multi Passthrough for unknown body kludges

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 PKT Hudson GoldBase EzyCom PCB WC
msg.num X X X X X X X X X
from / to / subject X X X X X X X X X
addr.orig / addr.dest X X X X X X X X X
date.written X X X X X X X X X
date.received X X X X
area X 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 X
attr.crash X X X X X X X
attr.received X X X X X X X X
attr.sent X X X X X X X X
attr.killsent X X X X X X X
attr.local X X X X X X X X
attr.hold X X X X X X
attr.fileattach X X X X X X X
attr.returnreceipt X X X X X X
attr.deleted X X X X X X X
msgid X X X X
replyid X X X X
pid X X X X
flags X X X X
seen-by X X X X
path X X X X
Format-specific (<fmt>.*) X 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.)