Contributor: MARTIN WOODS

{
 WK> I was wondering if anyone has either the layout for a *.MSG
 WK> packet or knows of a unit to generate and process *.MSG packets.
}

unit fidomsg;  { See 2 demo programs attached below !! }
Interface
uses dos;
const
  MsgSize = 32768;
type
AddressType = record
                Zone  : Byte;
                Net   : Word;
                Node  : Word;
                Point : Word;
                Domain: String[15];
              end;

TxtPtrType = ^TxtRecType;
TxtRecType = array[1..MsgSize] of char;

String36    = string[36];
String72    = string[72];
String20    = string[20];
FMsgType =    record
                FromUserName : String36;
                ToUserName   : String36;
                Subject      : String72;
                DateTime     : String20;
                Origin       : AddressType;
                Destination  : AddressType;
                NextReply    : word;
                MsgTxtPtr    : TxtPtrType;
              end;

procedure LoadMsg(var Msg: FMsgType; MsgFilePath : PathStr; var Result: byte);
procedure GetMsgHeap    (var Msg: FMsgType);
procedure DisposeMsgHeap(var Msg: FMsgType);

 Implementation

procedure GetMsgHeap(var Msg: FMsgType);
begin
  New(Msg.MsgTxtPtr);
end;

procedure DisposeMsgHeap(var Msg: FMsgType);
begin
  Dispose(Msg.MsgTxtPtr);
end;

procedure LoadMsg(var Msg: FMsgType; MsgFilePath : PathStr; var Result: byte);

type
  MsgHeaderType =    record
                       HFromUserName : array[1..36] of char;
                       HToUserName   : array[1..36] of char;
                       HSubject      : array[1..72] of char;
                       HDateTime     : array[1..20] of char;
                       HTimesRead    : word;
                       HDestNode     : word;
                       HOrigNode     : word;
                       HCost         : word;
                       HOrigNet      : word;
                       HDestNet      : word;
                       HFiller       : array[1..8] of char;
                       HReplyto      : word;
                       HAttribute    : word;
                       HNextReply    : word;
                      end;
var
  i : word;
  ReadResult : word;
  MsgFile : file;
  MsgHead : MsgHeaderType;
begin
  assign(MsgFile,MsgFilePath);
  {$I-}
  reset(MsgFile,1);
  {$I+}
  Result := IoResult;
  if result>0 then exit;
  fillchar(MsgHead,SizeOf(MsgHead),#00);
  fillchar(Msg.MsgTxtPtr^,MsgSize,#00);
  BlockRead(MsgFile,MsgHead,Sizeof(MsgHead));           {Read Header Info}
  BlockRead(MsgFile,Msg.MsgTxtPtr^,MsgSize,ReadResult); {Read Msg Text}
  If ReadResult = MsgSize then
  begin
    result := 255; {Msg > MsgSize}
    exit;
  end;
  with Msg, MsgHead do
  begin
    for i := 1 to 36 do
    begin
      if HFromUserName[i] = #00 then
      begin;
        FromUserName[0] := chr(i-1);
        i := 36;
      end;
      FromUserName[i] := HFromUserName[i];
    end;
    for i := 1 to 36 do
    begin
      if HToUserName[i]   = #00 then
      begin
        ToUserName[0] := chr(i-1);
        i := 36;
      end;
      ToUserName[i] := HToUserName[i];
    end;
    for i := 1 to 72 do
    begin
      if HSubject[i] = #00 then
      begin
        Subject[0] := chr(i-1);
        i := 72;
      end;
      Subject[i] := HSubject[i];
    end;
    for i := 1 to 20 do
    begin
      if HDateTime[i] = #00 then
      begin
        DateTime[0] := chr(i-1);
        i := 20;
      end;
      DateTime[i] := HDateTime[i];
    end;
    Destination.Zone := 1;
    Destination.Node := HDestNode;
    Destination.Net  := HDestNet;
    Destination.Point := 0;
    Origin.Zone := 1;
    Origin.Node      := HOrigNode;
    Origin.Net       := HOrigNet;
    Origin.Point := 0;
    NextReply        := HNextReply;
  end;
  close(MsgFile);
end;
end.

{ --------------------   DEMO PROGRAM --------------------- }

program DELMSGBY; { A program to kill all FIDOnet messages by a
                    certain person }

{$M 16384,0,65536}

uses dos,fidomsg;

var foo      :byte;
    nametodel:string;
    msg      :FMsgType;
    s        :searchrec;

function upstr(st:string):string;                { string processor that   }
var a:string;                                    { makes all uppercase and }
begin                                            { removes spaces          }
   a:='';
   for foo:=1 to length(st) do
   begin
      If st[foo]<>#32 then a:=a+upcase(st[foo]);
   end;
   upstr:=a;
end;

begin
   if paramcount<1 then          { If they don't know how to use this, then }
   begin
      writeln;
      writeln(' Usage: DELMSGBY [firstname] [lastname]');   { Tell them     }
      writeln;
   end
   else                       { Otherwise, they DO know how to use this, so }
   begin
      nametodel:='';
      for foo:=1 to paramcount do          { Get the name they don't like}         nametodel:=nametodel+' '+paramstr(foo);
      findfirst('*.MSG',Anyfile,s);        { And search all .MSG files for it}      while (DosError=0) do                { If a file is found then}      begin
         GetMsgHeap(msg);                     { Make space on the heap for it}         loadmsg(msg,fexpand(s.name),foo);    { Load it }
         If (upstr(msg.FromUserName)=upstr(nametodel)) then
         begin                           { If the message if from the bad guy}            swapvectors;                 {     then delete it. I used EXEC so}            exec(getenv('COMSPEC'),' /C '+'Del '+fexpand(s.name)); { you can}            swapvectors;                 { easily move, or rename it.}            writeln('Deleting '+fexpand(s.name)+'. It''s Contaminated!');
         end;
         DisposeMsgHeap(msg);            { Done w/ that message, so take back}         findnext(s);                    { the heap space. Then find another}      end;                               { Message to check. }
   end;
end.

{ ---------------------------   DEMO PROGRAM ----------------------------}

{this is a stand alone *.msg reader}
uses dos,crt;
Type FidoHeader=record {structure of the Message Header}
        WhoTheMessageIsFrom,
        WhoTheMessageItTo   : Array[1..36] of Char; {ASCIIZ Strings}
        MessageSubject      : Array[1..72] of Char;
        MessageDate         : Array[1..20] of Char;
                {The Message Date is an ASCIIZ string following this
                format: DD MMM YY  HH:MM:SS-20 Characters Total
                Example: 01 Jun 94 20:00:00 is June 1st 1994 at 8:00PM
                But SeaDog uses a slightly different version and you
                might want to account for that, unfortunately I can't
                remember the exact format, also SLMAIL for SearchLight
                BBS only puts one space between the year and the hour
                even though it's supposed to be 2, I'm surprised this
                hasn't thrown mailers of other BBS programs}
        TimesTheMessageWasRead,
        DestinationNode,
        OriginalNode,
        CostofTheMessage,
        OriginalNet,
        DestinationNet      : Integer;
                {Note: TimesTheMessageWasRead & CostofTheMessage are
                usually ignored when being exported from the BBS and can
                be ignored when importing into a BBS}
        DateWritten,
        DateArrived         : LongInt;
                {I'm not sure how the dates are stored in here, but
                they're usually ignored}
        MessageToWhichThisRepliesTo: Integer;{Irrevelant over a network}
        Arrtibutes          : Word;
                {Bit Field:
                    Bit 0 Private Message
                        1 Crashmail
                        2 Message Was Read
                        3 Message Was Sent
                        4 File Attatched, Filename in subject
                        5 Forwarded Message
                        6 Orphan Message ???
                        7 Kill After Its Sent (I think)
                        8 Message Originated Here (local)
                        9 Hold
                        10 Reserved
                        11 File Request, Filenames in Subject
                        12 Return Receipt Requested
                        13 This message is a Return Receipt
                        14 Audit Trail Requested
                        15 Update Request }
        UnReply             : Integer; {I have No Idea}
End;

Type FidoMsg=record
   msgchar : char;
end;

{The Message Text follows terminated by either a Null (#0) or to Cr's #13#13.
Also all paragraphs are supposed to end with a Hard CR (#141) and you can
ignoreany #13 and reformat the text for your own program, also any lines
starting with^A (#1) should not be imported into the BBS, they are control
lines... thecontents of these lines varies so you'll have to find out that on
your own }
var
  header : fidoheader;
  headerf: file of fidoheader;
  MsgTxt : FidoMsg;
  MsgTxtf: file of FidoMsg;
  DirInfo: SearchRec;
  ch,cx : char;
  cr,count : shortint;
  i:byte;
  l : string;
  s : string;
  howlong : byte;
begin
  FindFirst('*.MSG', Archive, DirInfo);
  while DosError = 0 do
  begin
    window(1,1,80,25);
    clrscr;
    textcolor(lightgreen);
    WriteLn(DirInfo.Name);
    textcolor(green);
    assign(headerf,DirInfo.Name);
    reset(headerf);
    read(headerf,header);
    with header do
    begin
        Writeln('From:  ',WhoTheMessageIsFrom);
        Writeln('To  :  ',WhoTheMessageItTo);
        Writeln('Subj:  ',MessageSubject);
        Writeln('Date:  ',MessageDate);
    end;
    textcolor(white);
Writeln('様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
 様様様');    window(1,wherey,80,25);
    textcolor(cyan);
    close(headerf);
    assign(MsgTxtF,DirInfo.Name);
    reset(MsgTxtF);
    seek(MsgTxtF,sizeof(header));
    cr := 0;
    count := 0;
    l := '';
    repeat
      read(MsgTxtF,MsgTxt);
      ch := MsgTxt.msgchar;
      if not (ch in [#10,#13]) then
      begin
        l := l + ch;
        howlong := length(l);
      end;
      if keypressed then
      begin
        cx := readkey;
        if cx = #27 then halt;
      end;
      if length(l) > 78 then
      begin
        count := length(l);
        while (count > 60) and (l[count] <> ' ') do dec(count);
        writeln(l,copy(l,1,count));
        delete(l,count,length(l));
      end;
      if ch = #13 then
      begin
        writeln(l);
        l := '';
        howlong := 0;
      end;
      if pos('these things?',l) > 0 then
      begin
        write
      end;
      if wherey > 15 then
      begin
        textcolor(12);
        writeln;

        write('Press enter: ');
        readln;

        clrscr;
        textcolor(cyan);
      end;

    until eof(MsgTxtF) or (ioresult > 0);
    if l > '' then
    begin
      writeln(l);
      l := '';
    end;
    textcolor(11);
    write('End of Msg: ');
    textcolor(7);
    cx := readkey;
    if cx = #27 then halt;
    clrscr;
    FindNext(DirInfo);
  end;
  textcolor(7);
end.

end.