Contributor: KELLY DROWN

{
> Do anyone have code for extracting a message from a pkt file? I realy
> need something that does it. OOP or non OOP doesn't matter.

Well, I found this searching my HDD. Its quite old and not written by me,
but I think this should do it. When not, start digging on FTSC*.* files
(don't remember the exact one)
}

Unit FidoNet;     { Beta Copy - Rev 6/5/89 - Tested 6/20/89  Ver. 0.31 }

           { FIDONET UNIT by Kelly Drown, Copyright (C)1988,89-LCP  }
           {                                   All rights reserved  }
           { If you use this unit in your own programming, I ask    }
           { only that you give me credit in your documentation.    }
           { I ask this instead of money. All of the following code }
           { is covered under the copyright of Laser Computing Co.  }
           { and may be used in your own programming provided the   }
           { terms above have been satisfactorily met.              }

INTERFACE

Uses Dos,
     Crt,
     StrnTTT5,  { TechnoJocks Turbo Toolkit v5.0 }
     MiscTTT5;


Type
      NetMsg = Record        { NetMessage Record Structure }
  From,
  Too        : String[35];
  Subject    : String[71];
  Date       : String[19];
  TimesRead,
  DestNode,
  OrigNode,
  Cost,
  OrigNet,
  DestNet,
  ReplyTo,
  Attr,
  NextReply  : Word;
  AreaName   : String[20];
     End;

   PktHeader = Record        { Packet Header of Packet }
                OrigNode,
                DestNode,
                Year,
                Month,
                Day,
                Hour,
                Minute,
                Second,
                Baud,
                OrigNet,
                DestNet     : Word;
               End;

  PktMessage = Record        { Packet Header of each individual message }
                OrigNode,
                DestNode,
                OrigNet,
                DestNet,
                Attr,
                Cost        : Word;
                Date        : String[19];
                Too         : String[35];
                From        : String[35];
                Subject     : String[71];
                AreaName    : String[20];
               End;

 ArchiveName = Record        { Internal Record Structure used for     }
                MyNet,       { determining the name of of an echomail }
                MyNode,      { archive. i.e. 00FA1FD3.MO1             }
                HisNet,
                HisNode     : Word;
               End;

Const                        { Attribute Flags }
      _Private  = $0001;
      _Crash    = $0002;
      _Recvd    = $0004;
      _Sent     = $0008;
      _File     = $0010;
      _Forward  = $0020;     { Also know as In-Transit }
      _Orphan   = $0040;
      _KillSent = $0080;
      _Local    = $0100;
      _Hold     = $0200;
      _Freq     = $0800;

      Status    : Array[1..12] Of String[3] = ('Jan','Feb','Mar','Apr','May',
                  'Jun','Jul','Aug','Sep','Oct','Nov','Dec');

Var Net    : NetMsg;
    PH     : PktHeader;
    PM     : PktMessage;
    ArcN   : ArchiveName;

Function  PacketName     : String;
Function  PacketMessage  : String;
Function  PacketHeader   : String;
Function  NetMessage     : String;
Function  GetPath(Var FName : String) : Boolean;
Function  GetNet(GN : String) : String;
Function  GetNode(GN : String) : String;
Function  MsgDateStamp   : String;
Function  LastMsgNum( _NetPath : String ) : Integer;
Function  Hex (n : word) : String;
Function  ArcName        : String;
Procedure ExpandNodeNumbers(Var List : String; VAR TotalNumber : Integer );
Procedure Conv_NetNode(NetNode : String; VAR Net, Node : Word);

IMPLEMENTATION

{-------------------------------------------------------------------------}
Function PacketName : String;
         { Creates and returns a unique Packet name }

Var h,m,s,hs     : Word;
    yr,mo,da,dow : Word;
    WrkStr       : String;
Begin
  WrkStr := '';
  GetTime(h,m,s,hs);
  GetDate(yr,mo,da,dow);

  WrkStr := PadRight(Int_To_Str(da),2,'0')
           +PadRight(Int_To_Str(h),2,'0')
           +PadRight(Int_To_Str(m),2,'0')
    +PadRight(Int_To_Str(s),2,'0');

  PacketName := WrkStr + '.PKT';
End;
{-------------------------------------------------------------------------}
Function PacketMessage : String;
         { Returns a Packet message header }

Var Hdr : String;

Begin
  Hdr := '';

  Hdr := #2#0                { Type #2 packets... Type #1 is obsolete }
         +Chr(Lo(PM.OrigNode))+Chr(Hi(PM.OrigNode))
  +Chr(Lo(PM.DestNode))+Chr(Hi(PM.DestNode))
  +Chr(Lo(PM.OrigNet))+Chr(Hi(PM.OrigNet))
  +Chr(Lo(PM.DestNet))+Chr(Hi(PM.DestNet))
  +Chr(Lo(PM.Attr))+Chr(Hi(PM.Attr))
  +Chr(Lo(PM.Cost))+Chr(Hi(PM.Cost))
  +PM.Date+#0
  +PM.Too+#0
  +PM.From+#0
  +PM.Subject+#0
         +Upper(PM.AreaName);

  PacketMessage := Hdr;
End;
{-------------------------------------------------------------------------}
Function PacketHeader : String;
         { Returns a Packet Header String }

Var Hdr : String;

Begin
  Hdr := '';

  Hdr := Chr(Lo(PH.OrigNode))+Chr(Hi(PH.OrigNode))
  +Chr(Lo(PH.DestNode))+Chr(Hi(PH.DestNode))
         +Chr(Lo(PH.Year))+Chr(Hi(PH.Year))
         +Chr(Lo(PH.Month))+Chr(Hi(PH.Month))
         +Chr(Lo(PH.Day))+Chr(Hi(PH.Day))
         +Chr(Lo(PH.Hour))+Chr(Hi(PH.Hour))
         +Chr(Lo(PH.Minute))+Chr(Hi(PH.Minute))
         +Chr(Lo(PH.Second))+Chr(Hi(PH.Second))
         +Chr(Lo(PH.Baud))+Chr(Hi(PH.Baud))
         +#2#0
         +Chr(Lo(PH.OrigNet))+Chr(Hi(PH.OrigNet))
         +Chr(Lo(PH.DestNet))+Chr(Hi(PH.DestNet))
         +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0   { Null Field Fill Space }
         +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0;

  PacketHeader := Hdr;
End;
{-------------------------------------------------------------------------}
Function NetMessage : String;
         { Returns a NetMessage header string }

Var Hdr : String;

Begin
  Hdr := '';

  Hdr := PadLeft(Net.From,36,#0);
  Hdr := Hdr + PadLeft(Net.Too,36,#0)
             + PadLeft(Net.Subject,72,#0)
             + PadRight(Net.Date,19,' ')+#0
             + Chr(Lo(Net.TimesRead))+Chr(Hi(Net.TimesRead))
             + Chr(Lo(Net.DestNode))+Chr(Hi(Net.DestNode))
             + Chr(Lo(Net.OrigNode))+Chr(Hi(Net.OrigNode))
             + Chr(Lo(Net.Cost))+Chr(Hi(Net.Cost))
             + Chr(Lo(Net.OrigNet))+Chr(Hi(Net.OrigNet))
             + Chr(Lo(Net.DestNet))+Chr(Hi(Net.DestNet))
             + #0#0#0#0#0#0#0#0
             + Chr(Lo(Net.ReplyTo))+Chr(Hi(Net.ReplyTo))
             + Chr(Lo(Net.Attr))+Chr(Hi(Net.Attr))
             + Chr(Lo(Net.NextReply))+Chr(Hi(Net.NextReply))
             + Upper(Net.AreaName);

  NetMessage := Hdr;
End;
{-------------------------------------------------------------------------}
Function GetPath(Var FName : String) : Boolean;
         { Returns the FULL Path and filename for a filename if the file  }
         { is found in the path. }

Var Str1,Str2 : String;
    NR        : Byte;
    HomeDir   : String;

Begin
  HomeDir := FExpand(FName);
  If Exist(HomeDir) Then Begin
      FName := HomeDir;
      GetPath := True;
      Exit;
    End;

  Str1 := GetEnv('PATH');
  For NR := 1 to Length(Str1) DO IF Str1[NR] = ';' Then Str1[NR] := ' ';
  For NR := 1 to WordCnt(Str1) DO
   Begin
    Str2 := ExtractWords(NR,1,Str1)+'\'+FName;
    IF Exist(Str2) Then Begin
      FName := Str2;
      GetPath := True;
      Exit;
    End;
   End;
   GetPath := False;
End;
{-------------------------------------------------------------------------}
Function MsgDateStamp : String;  { Creates Fido standard- 01 Jan 89 21:05:18 }
Var h,m,s,hs          : Word;    { Standard message header time/date stamp   }
    y,mo,d,dow        : Word;
    Tmp,
    o1,o2,o3          : String;

Begin
  o1 := '';
  o2 := '';
  o3 := '';
  tmp := '';
  GetDate(y,mo,d,dow);
  GetTime(h,m,s,hs);
  o1 := PadRight(Int_To_Str(d),2,'0');
  o2 := Status[mo];
  o3 := Last(2,Int_To_Str(y));
  Tmp := Concat( o1,' ',o2,' ',o3,'  ');
  o1 := PadRight(Int_To_Str(h),2,'0');
  o2 := PadRight(Int_To_Str(m),2,'0');
  o3 := PadRight(Int_To_Str(s),2,'0');
  Tmp := Tmp + Concat(o1,':',o2,':',o3);
  MsgDateStamp := Tmp;
End;
{-------------------------------------------------------------------------}
Function MsgToNum( Fnm : String ) : Integer; { Used Internally by LastMsgNum }
Var p : Byte;
Begin
  p        := Pos('.',Fnm);
  Fnm      := First(p-1,Fnm);
  MsgToNum := Str_To_Int(Fnm);
End;
{-------------------------------------------------------------------------}
Function LastMsgNum( _NetPath : String ) : Integer;
         { Returns the highest numbered xxx.MSG in NetPath directory }

Var
    _Path   : String;
    Temp1,
    Temp2   : String;
    Len     : Byte;
    DxirInf  : SearchRec;
    Num,
    Num1    : Integer;

Begin
  Num   := 0;
  Num1  := 0;
  Temp1 := '';
  Temp2 := '';
  _Path := '';
  _Path := _NetPath + '\*.MSG';

  FindFirst( _Path, Archive, DxirInf );
  While DosError = 0 DO
  Begin
    Temp1 := DxirInf.Name;
    Num1 := MsgToNum(Temp1);
    IF Num1 > Num Then Num := Num1;
    FindNext(DxirInf);
  End;

  IF Num = 0 Then Num := 1;
  LastMsgNum := Num;
End;
{-------------------------------------------------------------------------}
Function Hex(N : Word) : String;
         { Converts an integer or word to it's Hex equivelent }

Var
  L : string[16];
  BHi,
  BLo : byte;

Begin
  L := '0123456789abcdef';
  BHi := Hi(n);
  BLo := Lo(n);
  Hex := copy(L,succ(BHi shr 4),1) +
         copy(L,succ(BHi and 15),1) +
         copy(L,succ(BLo shr 4),1) +
         copy(L,succ(BLo and 15),1);
End;
{-------------------------------------------------------------------------}
Function ArcName : String;
         { Returns the proper name of an echomail archive }

Var C1,C2 : LongInt;
Begin
  C1 := 0; C2 := 0;
  C1 := ArcN.MyNet - ArcN.HisNet;
  C2 := ArcN.MyNode - ArcN.HisNode;
  If C1 < 0 Then C1 := 65535 + C1;
  If C2 < 0 Then C2 := 65535 + C2;
  ArcName := Hex(C1) + Hex(C2);
End;
{-------------------------------------------------------------------------}
Function GetNet( GN : String ) : String;
         { Returns the NET portion of a Net/Node string }

Var P : Byte;
Begin
  P := Pos('/',GN);
  GetNet := First(P-1,GN);
End;
{-------------------------------------------------------------------------}
Function GetNode( GN : String ) : String;
         { Returns the NODE portion of a Net/Node string }

Var P : Byte;
Begin
  P := Pos('/',GN);
  GetNode := Last(Length(GN)-P,GN);
End;
{-------------------------------------------------------------------------}
Procedure ExpandNodeNumbers(Var List : String; VAR TotalNumber : Integer );

        { Expands a list of short form node numbers to thier proper       }
        { Net/Node representations. Example:                              }
        { The string: 170/100 101 102 5 114/12 15 17 166/225 226          }
        { Would return: 170/100 170/101 170/102 170/5 114/12 114/15 etc.. }

Var Net,NetNode  : String[10];
    HoldStr,
    WS1          : String;
    N1           : Integer;

Begin
  Net := '';
  NetNode := '';
  HoldStr := '';
  WS1 := '';
  N1 := 0;
  TotalNumber := 0;
  TotalNumber := WordCnt(List);

  For N1 := 1 to TotalNumber DO Begin
    WS1 := ExtractWords(N1,1,List);
    IF Pos('/',WS1) <> 0 Then Begin Net := GetNet(WS1)+'/'; NetNode := WS1;
    End ELSE NetNode := Net+WS1;
    HoldStr := HoldStr + ' ' + Strip('A',' ',NetNode);

  End;
End;
{-------------------------------------------------------------------------}
Procedure Conv_NetNode(NetNode : String; VAR Net, Node : Word);
         { Returns NET and NODE as words from a Net/Node string }

Var WStr : String[6];
Begin
  Wstr := GetNet(NetNode);
  Net  := Str_To_Int(Wstr);
  Wstr := GetNode(NetNode);
  Node := Str_To_Int(Wstr);
End;
{-------------------------------------------------------------------------}

Begin
         { Initialize the data structures }

  FillChar(Net,SizeOf(Net),#0);
  FillChar(PM,SizeOf(PM),#0);
  FillChar(PH,SizeOf(PH),#0);
  FillChar(ArcN,SizeOf(ArcN),#0);

End. {Unit}