Files
fpc-msgbase/examples/example_read.pas
Ken Johnson 6b225fedfc 0.4.0: PKT moves to fpc-ftn-transport (breaking change)
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.
2026-04-18 11:32:42 -07:00

131 lines
3.2 KiB
ObjectPascal

{
example_read.pas - open a message base via the unified API,
walk every message, dump a one-line summary.
usage: example_read <format> <path>
format : hudson | jam | squish | msg | pcboard | ezycom |
goldbase | auto
path : directory or basename the backend expects
Example:
example_read hudson /home/ken/fidonet/msg/hudson
}
program example_read;
{$mode objfpc}{$H+}
uses
SysUtils,
ma.types, ma.events, ma.api,
ma.fmt.hudson, ma.fmt.hudson.uni,
ma.fmt.jam, ma.fmt.jam.uni,
ma.fmt.squish, ma.fmt.squish.uni,
ma.fmt.msg, ma.fmt.msg.uni,
ma.fmt.pcboard, ma.fmt.pcboard.uni,
ma.fmt.ezycom, ma.fmt.ezycom.uni,
ma.fmt.goldbase, ma.fmt.goldbase.uni;
type
TLogger = class
procedure OnLog(Level: TMsgEventType;
const Source, Msg: AnsiString);
end;
procedure TLogger.OnLog(Level: TMsgEventType;
const Source, Msg: AnsiString);
begin
WriteLn('[', EventTypeToStr(Level), '] ', Source, ': ', Msg);
end;
var
gLogger: TLogger;
function ParseFormat(const S: string; out AFormat: TMsgBaseFormat;
out AAuto: boolean): boolean;
begin
AAuto := False;
Result := True;
case LowerCase(S) of
'hudson': AFormat := mbfHudson;
'jam': AFormat := mbfJam;
'squish': AFormat := mbfSquish;
'msg': AFormat := mbfMsg;
'pcboard': AFormat := mbfPCBoard;
'ezycom': AFormat := mbfEzyCom;
'goldbase': AFormat := mbfGoldBase;
'wildcat': AFormat := mbfWildcat;
'auto': AAuto := True;
else
Result := False;
end;
end;
procedure Usage;
begin
WriteLn('Usage: example_read <format> <path>');
WriteLn(' formats: hudson jam squish msg pcboard ezycom goldbase wildcat auto');
Halt(2);
end;
var
fmtName: string;
path: string;
fmt: TMsgBaseFormat;
auto: boolean;
base: TMessageBase;
msg: TUniMessage;
i, n: longint;
begin
if ParamCount < 2 then Usage;
fmtName := ParamStr(1);
path := ParamStr(2);
if not ParseFormat(fmtName, fmt, auto) then Usage;
try
if auto then
base := MessageBaseOpenAuto(path, momReadOnly)
else
base := MessageBaseOpen(fmt, path, momReadOnly);
except
on E: Exception do begin
WriteLn('error: ', E.Message);
Halt(1);
end;
end;
if base = nil then begin
WriteLn('error: could not detect format at ', path);
Halt(1);
end;
gLogger := TLogger.Create;
base.Events.OnLog := @gLogger.OnLog;
if not base.Open then begin
WriteLn('error: Open returned False (base files missing?)');
base.Free;
Halt(1);
end;
try
n := base.MessageCount;
WriteLn('format: ', MSG_BASE_FORMAT_NAME[base.Format],
' path: ', base.BasePath,
' messages: ', n);
for i := 0 to n - 1 do
if base.ReadMessage(i, msg) then
WriteLn(Format('%5d %-20s -> %-20s %s',
[msg.Attributes.GetInt('msg.num'),
Copy(msg.Attributes.Get('from'), 1, 20),
Copy(msg.Attributes.Get('to'), 1, 20),
Copy(msg.Attributes.Get('subject'), 1, 40)]));
finally
base.Close;
base.Free;
gLogger.Free;
end;
end.