{$IFDEF WtrGate}{$IFDEF UseOvr}{$O+,F+}{$ENDIF}{$ENDIF}
UNIT FidoMsg;

{$I platform.inc}

{ FidoMsg                                                                 }
{                                                                         }
{ Deze unit bevat alle routines die nodig zijn om een FIDO *.MSG base     }
{ te manipuleren. Het is een samenraapsel van routines die eerst in       }
{ <FIDO> en <MSGS> bewaard werden.                                        }
{                                                                         }
{ 10-09-93 Hierheen verplaatst                                            }
{ 23-09-93 \*.MSG toevoegen aan searchpath bug gefixed.                   }


INTERFACE

USES Database;

CONST MsgIndexFilename = 'MSGINDEX.WG';

TYPE MsgOverlapRecord = RECORD
                              { at offset 176 / $B0 }
                              CASE INTEGER OF
                                        { Standard Format }
                                   0 : (DestZone,
                                        OrigZone,
                                        DestPoint,
                                        OrigPoint   : WORD);

                                        { Opus / FrontDoor format }
                                   1 : (DateWritten,
                                        DateArrived : LONGINT);

                                   2 : (A1,A2,A3,A4 : BYTE;
                                        B1,B2,B3,B4 : BYTE);

                              { DateWritten and DateArrived are packed }
                              { DOS dates with the high and low word   }
                              { exchanged as per the format used by    }
                              { Opus 1.03                              }
                        END;

TYPE FidoStoredHeader = RECORD
                              FromUserName  : ARRAY[0..35] OF CHAR;
                              ToUserName    : ARRAY[0..35] OF CHAR;
                              Subject       : ARRAY[0..71] OF CHAR;
                              DateTime      : ARRAY[0..19] OF CHAR;
                              TimesRead     : WORD;

                              DestNode,
                              OrigNode,
                              Cost          : WORD;

                              OrigNet,
                              DestNet       : WORD;

                              { Opus or not? }
                              Overlap       : MsgOverlapRecord;

                              ReplyTo       : WORD;
                              Attribute     : WORD;
                              NextReply     : WORD;
                        END;

PROCEDURE FidoMsg_ScanArea (AreaRecNr : AreaBaseRecordNrType;
                            AreaData : AreaBaseRecord;
                            IsPrimaryNetmailArea,IsBadArea : BOOLEAN);

PROCEDURE FidoMsg_ArcmailScan;

PROCEDURE FidoMsg_ImportMessage (AreaName,Target_Directory,DecodePath : STRING;
                                 DecodeFiles : BOOLEAN);

{ for moving from *.MSG to JAM/Squish/WildCat }
{$IFDEF WtrUtil}
PROCEDURE FidoMsgImport (AreaName,Aka : STRING; ForceNoKill,DeskTop : BOOLEAN);
{$ENDIF}

PROCEDURE FidoMsgClearMsgCount;
PROCEDURE FidoMsgInitMsgCount;
FUNCTION  FidoMsgGetNextMsgNum (Path : STRING) : STRING;

PROCEDURE FidoMsg_Rescan (VAR AreaData : AreaBaseRecord);


IMPLEMENTATION

USES Ramon,
     Crt,
     AreaMgr,
     Cfg,
     Logs,
     Fido,
     Globals,
     Dos,
     FBuffer,
     AreaBase,
     Msgs,
     UserBase,
     Strings,
     {Stats,}
     Fd,
     ListSrv,
     SwapMem,
     JAM,
     Squish,
     Decode,
     Routing,
     Start,
     UnixTime,
     {$IFDEF PLATFORM_OS2}
     Os2Base,
     {$ENDIF}
     Slice,
     {WildCat,}
     Scan,
     PackBuf,
     Trans,
     FlexTdb,
     Rescan;

     { Lijst met het aantal berichten in een fido *.MSG area }
TYPE MsgCounterPtr = ^MsgCounter;
     MsgCounter = RECORD
                        AreaId  : LONGINT;
                        AreaCnt : LONGINT;
                        AreaNxt : MsgCounterPtr;
                  END;

VAR CounterMsg : MsgCounterPtr;

CONST MsgCacheSize = 10000; { de meeste berichten zullen niet groter zijn }


{--------------------------------------------------------------------------}
{ FidoMsg_ScanArea                                                         }
{                                                                          }
{ Doorzoekt een directory op fido *.MSG berichten die verstuurd moeten     }
{ worden. Het path & de naam van de area moeten worden meegegeven, als de  }
{ areaname leeg is, wordt ervanuit gegaan dat het bericht een Netmail is.  }
{                                                                          }
{ RWI961218: Index toegevoegd. Iedere entry is een combinatie van de low   }
{            wordt van de date en size in een longint.                     }
{                                                                          }
PROCEDURE FidoMsg_ScanArea (AreaRecNr : AreaBaseRecordNrType;
                            AreaData : AreaBaseRecord; IsPrimaryNetmailArea,IsBadArea : BOOLEAN);

VAR ZoekFile      : SearchRec;
    InputFile     : FBufferType;
    FidoMsgHeader : FidoStoredHeader;
    IORes         : BYTE;
    MsgNr         : LONGINT;
    Error         : ValNop;
    TmpFile,
    DirectoryName,
    Regel,
    LastRegel     : STRING;
    FirstExport   : BOOLEAN;
    IndexFile     : FILE;
    IndexCheck,
    IndexCode     : LONGINT;
    Result        : ScanDeliverResultType;

LABEL FindNextMsg;

BEGIN
     IF (AreaData.FidoMsgPath = '') THEN
     BEGIN
          LogMessage (liConfig,'[Scan] Path not defined for *.MSG area '+AreaData.AreaName_F);
          Exit;
     END;

     FirstExport:=(NOT IsBadArea); { no additional logging during TOSSBAD }

     { houdt de stats bij van de lokale gebieden }
     UserDataRecNr:=NILRecordNr;
     DirectoryName:=AreaData.FidoMsgPath;

     { verwijder backspace aan het einde }
     IF (DirectoryName[Length (DirectoryName)] = '\') THEN
        Delete (DirectoryName,Length (DirectoryName),1);

     { kijk of de gegeven directory wel bestaat }
     FindFirst (DirectoryName,saDirAndFiles,Zoekfile);
     IF (Dos.DosError <> 0) THEN
     BEGIN
          LogMessage (liConfig,'Directory '+DirectoryName+' does not exist!');
          FindClose (ZoekFile);
          Exit;
     END;
     FindClose (ZoekFile);

     { zoek naar het eerste *.MSG bestand in deze directory }
     DirectoryName:=AreaData.FidoMsgPath;
     IF (DirectoryName[Length (DirectoryName)] <> '\') THEN
        DirectoryName:=DirectoryName+'\';

     FindFirst (DirectoryName+'*.MSG',saDirAndFiles,ZoekFile);
     IF (Dos.DosError = 18) THEN
     BEGIN
          FindClose (ZoekFile);
          Exit; { geen files }
     END;

     { open / create the message index file }
     Assign (IndexFile,DirectoryName+MsgIndexFilename);
     {$I-} Reset (IndexFile,1); {$I+} IORes:=IOResult;
     IF (IORes = 2) THEN
     BEGIN
          {$I-} ReWrite (IndexFile,1); {$I+} IORes:=IOResult;
     END;

     IF (IORes <> 0) THEN
     BEGIN
          LogDiskIOError (IORes,'Error accessing '+MsgIndexFilename);
          Exit;
     END;

     {$IFDEF LogFileIO}PostOpenF (IndexFile);{$ENDIF}
     PeekFiles;

     { doorloop de directory tot alle berichten zijn gevonden }
     WHILE (NOT GlobalAbort) AND (Dos.DosError = 0) DO
     BEGIN
          { controleer of het bericht begint met een decimale naam }
          Val (Copy (Zoekfile.Name,1,Pos ('.',Zoekfile.Name)-1),MsgNr,Error);

          { zo niet, raporteer dit aan de bevoegde instanties }
          IF (Error > 0) THEN
          BEGIN
               LogExtraMessage ('Ignoring invalid number in *.MSG filename '+ZoekFile.Name);
               GOTO FindNextMsg;
          END;

          IF ((Zoekfile.Attr AND 1{read-only}) <> 0) THEN
          BEGIN
               IF Config.LogDebug THEN
                  LogMessage (liGeneral,'Skipping locked message '+ZoekFile.Name);
               GOTO FindNextMsg;
          END;

          { update de index file }
          IndexCode:=(Zoekfile.Time SHL 16) OR (Zoekfile.Size AND 65535);

          { controleer de index }
          IF (NOT ForceCleanScan) AND (NOT IsBadArea) AND (Longint (MsgNr)*4 < FileSize (IndexFile)) THEN
          BEGIN
               {$I-}
               Seek (IndexFile,MsgNr*4);
               BlockRead (IndexFile,IndexCheck,4);
               {$I+}

               { this never happens with ARCmail messages }
               IF (IndexCheck = IndexCode) THEN
                  GOTO FindNextMsg;
          END;

          { update the index code }

          Slice_Now;

          IF KeyPressed AND (Ramon.ReadKey = kEsc) THEN
          BEGIN
               GlobalAbort:=TRUE;
               Break;
          END;

          { niet de index updaten als we alleen op zoek zijn naar file    }
          { attaches, want dan kunnen berichten nooit geexporteerd raken. }
          IF (NOT IsBadArea) THEN
          BEGIN
               {$I-}
               Seek (IndexFile,MsgNr*4);
               BlockWrite (IndexFile,IndexCode,4);
               {$I+} IORes:=IOResult;
               IF (IORes <> 0) THEN
                  LogDiskIOError (IORes,'Error updating *.MSG index at '+Longint2String (MsgNr*4));
          END;

          UpdateReadFile (DirectoryName+Zoekfile.Name,Zoekfile.Size);

          { probeer het bericht te openen }
          IF (NOT FBufferOpen (InputFile,DirectoryName+Zoekfile.Name,MsgCacheSize,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               { RWI 961005: added FBufferOpen result check, log and Continue (!!) }
               LogMessage (liFatal,'Failed to open '+Zoekfile.Name);
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { probeer de header in te lezen }
          IF (NOT FBBlockRead (InputFile,FidoMsgHeader,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               LogMessage (liFatal,'Unable to read from '+Zoekfile.Name);
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { nu kijken we of dit bericht niet verzonden moet worden }
          { RWI 960219: check voor Hold en Read verplaatst tot Na' de }
          {             file attach check.                            }
          IF (NOT IsBadArea) THEN
          BEGIN
               IF ((FidoMsgHeader.Attribute AND MSGSENT) <> 0) OR
                  ((FidoMsgHeader.Attribute AND MSGORPHAN) <> 0) OR
                  ((FidoMsgHeader.Attribute AND MSGFRQ) <> 0) THEN
               BEGIN
                    { Er staat een SENT vlag op het bericht, we negeren het dus }
                    { de geadresseerde heeft het bericht al gelezen het bericht }
                    { is niet lokaal, en niet geforward                         }

                    { RAWI 970531: sla berichten met een File Request vlag }
                    {              natuurlijk ook over..                   }
                    FBufferClose (InputFile);
                    GOTO FindNextMsg;
               END;

               { test op READ berichten of (HOLD en FrontDoor) }
               IF ((FidoMsgHeader.Attribute AND MSGREAD) <> 0) OR
     {RWI 960521} ((Config.FidoSystem = stFrontDoor) AND
     {RWI 941127}  ((FidoMsgHeader.Attribute AND MSGHOLD) <> 0)) THEN
               BEGIN
                    IF ((FidoMsgHeader.Attribute AND MSGFILE) = 0) THEN
                    BEGIN
                         { Read or Hold message, but not a file attach: skip it }
                         FBufferClose (InputFile);
                         GOTO FindNextMsg;
                    END;
               END;
          END; { isbadarea }

          { ---- initialisatie van de lokale variabelen ---- }

          LastRegel:='';

          Found_Path:=FALSE;
          Found_SeenBy:=FALSE;
          Found_Tear:=FALSE;
          Found_Origin:=FALSE;

          { maak eerst de interne bericht structuur leeg }
          MsgsEmpty;

          { vul dan opnieuw de header in }
          IF (NOT IsBadArea) THEN
          BEGIN
               IF (AreaData.AreaType = Area_Echo) THEN
               BEGIN
                    Msg.Ready_F:=Local_Echomail;
                    { vul de extra informatie in }
                    Msg.Area_F:=AreaData.AreaName_F;
                    { Stop de AREA: kludge in de eerste regel van het bericht }
                    {RAWI 971012: now done by PKT export
                    MsgsAddLineTo (Header_F,'AREA:'+AreaData.AreaName_F);
                    }
               END ELSE
                   Msg.Ready_F:=Local_Netmail;
          END;

          Msg.FromUser_F:=DeleteBackSpaces (StrPas (FidoMsgHeader.FromUserName));
          Msg.Stored_ToUser:=DeleteBackSpaces (StrPas (FidoMsgHeader.ToUserName));
          Msg.Subj_F:=DeleteBackSpaces (StrPas (FidoMsgHeader.Subject));
          Msg.Date_F:=FidoCorrectDate (FidoMsgHeader.DateTime);
          Msg.Cost_F:=FidoMsgHeader.Cost;
          Msg.Attr_F:=FidoMsgHeader.Attribute;

          { Let op ! Over het algemeen zetten alle editors rotzooi }
          { in de zone + point velden. Als er een zone in het      }
          { bericht staat halen we hem wel uit de MSGID ofzo.      }

          { FrontDoor/Opus zetten in die velden twee datums }

          Msg.FromAddr_F.Zone:=0;
          Msg.FromAddr_F.Net:=FidoMsgHeader.origNet;
          Msg.FromAddr_F.Node:=FidoMsgHeader.origNode;
          Msg.FromAddr_F.Point:=0;

          Msg.Stored_ToAddr.Zone:=0;
          Msg.Stored_ToAddr.Net:=FidoMsgHeader.destNet;
          Msg.Stored_ToAddr.Node:=FidoMsgHeader.destNode;
          Msg.Stored_ToAddr.Point:=0;

          {## do not have to read the entire message when in
              SystemMode == smFDSCAN. In that case we are only
              interested in the kludges. We currently read the
              entire message, which can be several KB large
              and require swapping!}
          WHILE FBReadLnCR (InputFile,Regel) AND (Regel <> #0) DO
          BEGIN
               { soft CR's strippen }
               WHILE (Pos (#$8D,Regel) > 0) DO
                     Delete (Regel,Pos (#$8D,Regel),1);

               { FidoAddLineToMessage gaat er vanuit dat de nodige }
               { cr,lf enzo al in Regel zitten. Dat hebben we dus  }
               { precies nodig om regels langer dan 255 tekens toe }
               { te kunnen voegen...                               }
               FidoAddLineToMessage (Regel,LastRegel);

          END; { while }

          FidoAddLastLine (LastRegel);

          { ignore LOcKed messages }
          IF ((Msg.ExtAttr_F AND EXTMSGLOK) <> 0) THEN
          BEGIN
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { WTRBAD_AREA kludge sets Msg.BadAreaRecNr }
          IF IsBadArea AND (Msg.BadAreaRecNr = NILRecordNr) THEN
          BEGIN
               { Unknown area; skip message }
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { we no longer need the FBuffer cache, so we disable it }
          FBufferFreeCache (InputFile);

          { Als de FROM zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de Area AKA                                     }
          IF (Msg.FromAddr_F.Zone = 0) THEN
             IF (Msg.Ready_F = Local_Echomail) THEN
                FidoMergeAdres (Config.NodeNrs[AreaData.OriginAka],Msg.FromAddr_F)
             ELSE
                 {## check MSGID?}
                 FidoMergeAdres (Config.NodeNrs[1],Msg.FromAddr_F);

          { Als de TO zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de FROM zone.                                 }
          IF (Msg.Stored_ToAddr.Zone = 0) THEN
             Msg.Stored_ToAddr.Zone:=Msg.FromAddr_F.Zone;

          {----------------------------------------------------------------}
          { Frontdoor Netmail MODE                                         }
          {                                                                }
          { Controleer of we met een 'leeg' netmail bericht te maken       }
          { hebben dat met een file-attch heeft. Controleer vervolgens of  }
          { die file attach nog wel bestaat.                               }
          {                                                                }
          { Deze functie bestaat ALLEEN voor de Fido *.MSG routines,       }
          { Frontdoor kent (nog) geen andere formaten.                     }
          {----------------------------------------------------------------}

          { skip mail FrontDoor ARCmail messages }
          IF (Config.FidoSystem = stFrontdoor) AND
             (Msg.Ready_F = Local_Netmail) AND
             FidoOurAdres (Msg.FromAddr_F) AND
             (Msg.FromUser_F = 'ARCmail') THEN
          BEGIN
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { Controleer of het bericht voor Areafix, listserver of gateway }
          { is EN of het uberhaupt wel lokaal is.                         }
          IF (NOT IsBadArea) THEN
          BEGIN
               IF (NOT FidoCheckNetmail (IsPrimaryNetmailArea,Msg.Stored_ToUser,Msg.Stored_ToAddr)) THEN
               BEGIN
                    FBufferClose (InputFile);
                    GOTO FindNextMsg;
               END;
          END;

          { verwijderen van lokale vlaggen van een bericht }
          Msg.Attr_F:=Msg.Attr_F AND ($FFFF-MSGLOCAL-MSGXX2);

          { alleen als het bericht een Echomail is }
          IF (Msg.Ready_F = Local_Echomail) THEN
             FidoFinishEchomailExport (AreaData);  { fix Origin }

          IF FirstExport THEN
          BEGIN
               FirstExport:=FALSE;
               LogMessage (liTrivial,'Exporting from '+AreaData.AreaName_F+' (*.MSG)');
          END;

          { werk de statistieken bij... }
          IF (Msg.Ready_F = Local_Netmail) THEN
          BEGIN
               {Inc (FidoProcessStatus.NetCount) { Netmail }
               IF Config.LogExportedMsgs THEN
                  LogMessage (liTrivial,'  Exporting '+Zoekfile.Name+
                                        ' for "'+Msg.Stored_ToUser+'"%'+Fido2Str (Msg.Stored_ToAddr));
          END ELSE
          BEGIN
               IF IsBadArea THEN
                  LogMessage (liGeneral,'  Re-tossing BAD message to '+Msg.Area_F);

               { echomail }
               {### stats}
               {
               UpdateAreaStats (GetAreaBaseRecordNrByAreaName_F (AreaData.AreaName_F),Msg.MsgSize);
               UpdateUserStats (NILRecordNr,EchoFrom,Msg.MsgSize);
               }
          END;

          UpdateInfoNr (INFO_MsgScan_Msgs,1);
          UpdateInfoNr (INFO_MsgScan_Bytes,ZoekFile.Size);

          IF (Msg.Ready_F IN [Netmail,Local_Netmail]) then
             UpdateInfoNr (INFO_MsgScan_Net,1)
          ELSE
              UpdateInfoNr (INFO_MsgScan_Echo,1);

          Result:=Scan_DeliverMessage (AreaRecNr,IsBadArea);

          { Nu moeten we de file voorzien van een 'SENT' vlag, en als het }
          { een Kill/Sent vlag had verwijderen.                           }

          { Omdat ik geen zin heb om moeilijk te gaan doen,... ff heel    }
          { smerig. Maar omdat we de file hierna toch afsluiten...        }
          {                                                               }
          { We passeren hier de read cache van FBuffer om direct in de    }
          { file te gaan zitten klooien. Dit was minder werk dan om       }
          { FBUFFER geheel transparant te maken.                          }

          IF (Result = sdKill) THEN
          BEGIN
               { delete the message }
               FBufferClose (InputFile);
               {$I-} Erase (InputFile.Bestand); {$I+}
               IORes:=IOResult;
               IF (IORes > 0) THEN
                  LogDiskIOError (IORes,'[ScanFidoMsgArea] Unable to delete '+InputFile.Filename);
          END ELSE
          BEGIN
               {## must remove UNS flag from FLAGS kludge as well }
               {## maybe even re-write the entire FLAGS kludge?   }

               IF (Result = sdSent) THEN
                  FidoMsgHeader.Attribute:=FidoMsgHeader.Attribute OR MSGSENT;

               IF (Result = sdReceived) THEN
                  FidoMsgHeader.Attribute:=FidoMsgHeader.Attribute OR MSGREAD;

               IF (Result = sdOrphan) THEN
                  FidoMsgHeader.Attribute:=FidoMsgHeader.Attribute OR MSGORPHAN;

               { write the updated flags to disk }

               { update the header }
               {$I-}
               Seek (Inputfile.Bestand,0);
               BlockWrite (Inputfile.Bestand,FidoMsgHeader,SizeOf (FidoMsgHeader));
               {$I+}

               IORes:=IOResult;
               IF (IORes > 0) THEN
                  LogDiskIOError (IORes,'Unable to update *.MSG message header');

               FBufferClose (Inputfile);
          END;

 FindNextMsg:
          { en spring door naar de volgende file }
          { RWI 201094: Gaat dit ook goed als je een file verwijderd hebt? }
          {             In de *.PKT inlees routine gingen we steeds        }
          {             opnieuw verder door FindFirst uit te voeren...     }
          FindNext (Zoekfile);
     END; { while DosError=0  }

     {$IFDEF LogFileIO}PreCloseF (IndexFile);{$ENDIF}
     {$I-} Close (IndexFile); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
        LogDiskIOError (IORes,'Error closing *.MSG index file');

     FindClose (ZoekFile);

     MsgsEmpty;
END;


{--------------------------------------------------------------------------}
{ FidoMsg_ArcmailScan                                                      }
{                                                                          }
{ This routine searches the primary netmail area for messages written by   }
{ ARCmail. These are transport messages that FrontDoor and compatible      }
{ mailers use as their work queue. These messages have a file attached,    }
{ which will be transported to the system the message is addressed to.     }
{ This routine searches for these messages and keeps a log of which        }
{ messages are present. When packing, this information is used to decide   }
{ whether to create a new attachment or not.                               }
{ This routine used to be integrated with the FidoMsg_Scan routine, but    }
{ the cache in combination with an external rename utility was causing too }
{ many problems and differences. This routine uses another strategy where  }
{ only short length messages are opened and checked for the ARCmail name.  }
{ Information about the found messages is fed to the FD file.              }
{                                                                          }
PROCEDURE FidoMsg_ArcmailScan;

VAR DirectoryName : STRING;
    ZoekFile      : SearchRec;
    InputFile     : FBufferType;
    FidoMsgHeader : FidoStoredHeader;
    IORes         : BYTE;
    MsgNr         : LONGINT;
    Error         : ValNop;
    TmpFile,
    Regel,
    LastRegel     : STRING;
    Result        : ScanDeliverResultType;

LABEL FindNextMsg,
      CloseInputFileAndFindNextMsg;

BEGIN
     IF (Config.FidoSystem <> stFrontdoor) OR
        (Config.FidoNetmailType <> FidoMsgType) THEN
     BEGIN
          LogMessage (liReport,'FidoMsg_ArcmailScan: not supposed to be here!');
          Exit;
     END;

     DirectoryName:=Config.FidoNetmailPath;

     { remove the backspace at the end }
     IF (DirectoryName[Length (DirectoryName)] = '\') THEN
        Delete (DirectoryName,Length (DirectoryName),1);

     { check if the directory exists }
     FindFirst (DirectoryName,saDirAndFiles,Zoekfile);
     IF (Dos.DosError <> 0) THEN
     BEGIN
          LogMessage (liConfig,'Directory '+DirectoryName+' does not exist!');
          FindClose (ZoekFile);
          Exit;
     END;
     FindClose (ZoekFile);

     { search for the first *.MSG file in this directory }
     DirectoryName:=DirectoryName+'\';

     FindFirst (DirectoryName+'*.MSG',saDirAndFiles,ZoekFile);
     IF (Dos.DosError = 18) THEN
     BEGIN
          FindClose (ZoekFile);
          Exit; { geen files }
     END;

     { doorloop de directory tot alle berichten zijn gevonden }
     WHILE (NOT GlobalAbort) AND (Dos.DosError = 0) DO
     BEGIN
          { controleer of het bericht begint met een decimale naam }
          Val (Copy (ZoekFile.Name,1,Pos ('.',ZoekFile.Name)-1),MsgNr,Error);

          { zo niet, raporteer dit aan de bevoegde instanties }
          IF (Error > 0) THEN
          BEGIN
               LogMessage (liGeneral,'Ignoring invalid number in *.MSG filename '+ZoekFile.Name);
               GOTO FindNextMsg;
          END;

          IF ((Zoekfile.Attr AND 1{read-only}) <> 0) THEN
          BEGIN
               IF Config.LogDebug THEN
                  LogMessage (liGeneral,'Skipping locked message '+ZoekFile.Name);
               GOTO FindNextMsg;
          END;

          { check the length. ARCmail messages are always very short }
          IF (ZoekFile.Size > (SizeOf (FidoStoredHeader)+
                               40+   {from}
                               40+   {to}
                               80+   {subj}
                               40)) THEN
               GOTO FindNextMsg;

          Slice_Now;

          IF KeyPressed AND (Ramon.ReadKey = kEsc) THEN
          BEGIN
               GlobalAbort:=TRUE;
               Break;
          END;

          UpdateReadFile (DirectoryName+Zoekfile.Name,Zoekfile.Size);

          { probeer het bericht te openen }
          IF (NOT FBufferOpen (InputFile,DirectoryName+Zoekfile.Name,MsgCacheSize,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               { RWI 961005: added FBufferOpen result check, log and Continue (!!) }
               LogMessage (liFatal,'Failed to open '+Zoekfile.Name);
               GOTO CloseInputFileAndFindNextMsg;
          END;

          { probeer de header in te lezen }
          IF (NOT FBBlockRead (InputFile,FidoMsgHeader,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               LogMessage (liFatal,'Unable to read from '+Zoekfile.Name);
               GOTO CloseInputFileAndFindNextMsg;
          END;

          { skip the message if it has the Sent or Freq flag }
          { skip the message if it does not have the f/a flag }
          IF ((FidoMsgHeader.Attribute AND MSGSENT) <> 0) OR
             ((FidoMsgHeader.Attribute AND MSGFRQ) <> 0) OR
             ((FidoMsgHeader.Attribute AND MSGFILE) = 0) THEN
               GOTO CloseInputFileAndFindNextMsg;

          { check if written by "ARCmail" }
          IF (DeleteBackSpaces (StrPas (FidoMsgHeader.FromUserName)) <> 'ARCmail') THEN
               GOTO CloseInputFileAndFindNextMsg;

          MsgsEmpty;

          LastRegel:='';

          Msg.Ready_F:=Local_Netmail;

          Msg.FromUser_F:='ARCmail';
          Msg.Stored_ToUser:=DeleteBackSpaces (StrPas (FidoMsgHeader.ToUserName));
          Msg.Subj_F:=DeleteBackSpaces (StrPas (FidoMsgHeader.Subject));

          Msg.FromAddr_F.Zone:=0;
          Msg.FromAddr_F.Net:=FidoMsgHeader.origNet;
          Msg.FromAddr_F.Node:=FidoMsgHeader.origNode;
          Msg.FromAddr_F.Point:=0;

          Msg.Stored_ToAddr.Zone:=0;
          Msg.Stored_ToAddr.Net:=FidoMsgHeader.destNet;
          Msg.Stored_ToAddr.Node:=FidoMsgHeader.destNode;
          Msg.Stored_ToAddr.Point:=0;

          WHILE FBReadLnCR (InputFile,Regel) AND (Regel <> #0) DO
          BEGIN
               { soft CR's strippen }
               WHILE (Pos (#$8D,Regel) > 0) DO
                     Delete (Regel,Pos (#$8D,Regel),1);

               FidoAddLineToMessage (Regel,LastRegel);
          END; { while }

          FidoAddLastLine (LastRegel);

          { ignore LOcKed messages }
          IF ((Msg.ExtAttr_F AND EXTMSGLOK) <> 0) THEN
               GOTO CloseInputFileAndFindNextMsg;
 

          { we no longer need the FBuffer cache, so we disable it }
          FBufferFreeCache (InputFile);

          { Als de FROM zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de Area AKA                                     }
          IF (Msg.FromAddr_F.Zone = 0) THEN
             FidoMergeAdres (Config.NodeNrs[1],Msg.FromAddr_F);

          { als de TO zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de FROM zone.                                 }
          IF (Msg.Stored_ToAddr.Zone = 0) THEN
             Msg.Stored_ToAddr.Zone:=Msg.FromAddr_F.Zone;

          { check if written on our system }
          IF (NOT FidoOurAdres (Msg.FromAddr_F)) THEN
             GOTO CloseInputFileAndFindNextMsg;

          { check if the first file on the line still exists }
          TmpFile:=Msg.Subj_F;
          IF (Pos (' ',TmpFile) > 0) THEN
             TmpFile:=Copy (TmpFile,1,Pos (' ',TmpFile)-1);

          { de file moet een VOLLEDIG (incl. Drive!) path bevatten }
          IF (TmpFile[2] = ':'{C:\FILES}) AND (NOT ForceNoFAKill) THEN
             IF (NOT TestIfExist (TmpFile)) THEN
             BEGIN
                  LogMessage (liGeneral,'Attached file no longer exists for '+
                                        FBGetFilename (InputFile)+'; deleting');
                  FBufferClose (InputFile);
                  {$I-} Erase (InputFile.Bestand); {$I+}
                  IORes:=IOResult;
                  IF (IORes <> 0) THEN
                     LogDiskIOError (IORes,'Failed to delete empty file attach message');

                  GOTO FindNextMsg;
             END;

          { Als we hier aankomen hebben we dus een         }
          { fileattach voor een node gevonden, die nog     }
          { bestaat ook!                                   }
          { Kijk alleen nog ff of we de node wel kennen... }
          FrontDoorAddToList (Msg.Stored_ToAddr,TmpFile);

 CloseInputFileAndFindNextMsg:
          FBufferClose (InputFile);

 FindNextMsg:

          Slice_Now;
          FindNext (Zoekfile);
     END; { while DosError=0  }

     FindClose (ZoekFile);

     MsgsEmpty;
END;


{==========================================================================}
{##                          FIDO SAVE MSG                                 }
{==========================================================================}

VAR FidoMsgSave_OutFile : FILE;
    FidoMsgSave_OutName : STRING[80];

{--------------------------------------------------------------------------}
{ FidoMsgSave_Flush                                                        }
{                                                                          }
{ This routine is called by the PackBuf code during creation of a *.MSG    }
{ file to write a filled up buffer to disk.                                }
{                                                                          }
PROCEDURE FidoMsgSave_Flush (VAR Buffer; Count : WORD; APtr : POINTER); FAR;

VAR IORes : BYTE;

BEGIN
     {$I-} BlockWrite (FidoMsgSave_OutFile,Buffer,Count); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
        LogDiskIOError (IORes,'Error writing '+Byte2String (Count)+' bytes to '+FidoMsgSave_OutName)
     ELSE
         UpdateInfoNr (INFO_MsgSave_Bytes,Count);
END;


VAR FidoMsgSave_ReplaceMsgID : BOOLEAN;

{--------------------------------------------------------------------------}
{ Import_AddHeaderLine                                                     }
{                                                                          }
{ This routine is called for each line in a Header_U. It searches for the  }
{ MSGID kludge and replaces it for each split part.                        }
{                                                                          }
FUNCTION Import_AddHeaderLine (VAR Regel : STRING) : BOOLEAN; FAR;

VAR Temp : STRING;

BEGIN
     Temp:=TransFix_HeaderLine (Regel);

     Import_AddHeaderLine:=PackBuf_AddLine (Temp);
END;


{--------------------------------------------------------------------------}
{ Import_AddFooterLine                                                     }
{                                                                          }
FUNCTION Import_AddFooterLine (VAR Regel : STRING) : BOOLEAN; FAR;

VAR Temp : STRING;

BEGIN
     Temp:=TransFix_FooterLine (Regel);

     {## add strip SEEN-BY handling }

     Import_AddFooterLine:=PackBuf_AddLine (Temp);
END;


VAR AttachedFiles : STRING;

{--------------------------------------------------------------------------}
{ MsgImport_AttachFile                                                     }
{                                                                          }
{ This routine is called for each file that has been decoded. The path     }
{ points to the file, in the directory that was set for decoded files.     }
{ This function attaches the file to the current message by
{                                                                          }
PROCEDURE MsgImport_AttachFile (Path,OriginalName : STRING); FAR;
BEGIN
     LogMessage (liTrivial,'*.MSG: attaching file');
     {$IFDEF Pre}
     LogExtraMessage ('  Path: "'+Path+'"');
     LogExtraMessage ('  OriginalName: "'+OriginalName+'" (cannot store this)');
     {$ENDIF}

     IF (AttachedFiles <> '') THEN
        AttachedFiles:=AttachedFiles+' ';

     AttachedFiles:=AttachedFiles+Path;
END;


{--------------------------------------------------------------------------}
{ FidoMsg_ImportMessage                                                    }
{                                                                          }
{ Deze routine importeert een bericht in een lokale *.MSG base.            }
{                                                                          }
PROCEDURE FidoMsg_ImportMessage (AreaName,Target_Directory,DecodePath : STRING;
                                 DecodeFiles : BOOLEAN);

VAR SplitParts   : WORD;
    SplitBodyLen : LONGINT;

    {----------------------------------------------------------------------}
    { EstimateSplitParts                                                   }
    {                                                                      }
    { This routine is used by both the netmail and echomail PKT file       }
    { export routine to calculate the number of split parts for a message. }
    {                                                                      }
    PROCEDURE EstimateSplitParts;

    VAR HeaderLen,
        BodyLen      : LONGINT;
        SplitParts_R : REAL;

    BEGIN
         SplitParts:=0;
         SplitBodyLen:=MAXLONGINT;

         IF (Config.MaxFidoMsgLen = 0) THEN
            Exit; { no need to split }

         { calculate the size of the actual parts }
         HeaderLen:=0;

         IF (Msg.HeaderTop_F <> NIL) THEN
            Inc (HeaderLen,Msg.HeaderTop_F^.TotalRegelLength);

         IF (Msg.CopiedHeadersTop_F <> NIL) THEN
            Inc (HeaderLen,Msg.CopiedHeadersTop_F^.TotalRegelLength);

         IF (Msg.FooterTop_F <> NIL) THEN
            Inc (HeaderLen,Msg.FooterTop_F^.TotalRegelLength);

         { since we don't know the exact length of the follow parameters, }
         { we have to be a bit conservative. This could result in split   }
         { parts that could have been a few bytes longer and sometimes    }
         { one split part less, but that's better as having more split    }
         { parts as estimated.                                            }
         SplitBodyLen:=Config.MaxFidoMsgLen-
                       SizeOf (FidoStoredHeader)-
                       HeaderLen-
                       64-                  { SPLIT kludge }
                       200;                 { conservativeness compensation }

         { include the space required for the netmail kludges }
         IF (Msg.Ready_F IN [Netmail,Local_Netmail]) THEN
            Dec (SplitBodyLen,
                       25+                  { avg. #INTL } { err: 0-16 }
                       8+                   { avg. FMPT }  { err: 0-4 }
                       8);                  { avg. TOPT }  { err: 0-4 }

         { prevent too small split parts }
         IF (SplitBodyLen < 1024) THEN
         BEGIN
              LogMessage (liConfig,'Too small split parts for *.MSG import, limiting to 1Kb');
              SplitBodyLen:=1024;
         END;

         { sum the body parts that will not be extracted }
         BodyLen:=MsgsCalcBodyLen ({IncludeAttachments}(NOT DecodeFiles));

         SplitParts_R:=(BodyLen / SplitBodyLen);

         SplitParts:=Trunc (SplitParts_R);
         IF (SplitParts < SplitParts_R) THEN
            Inc (SplitParts);
    END;

{FidoMsg_ImportMessage}

VAR PosRec        : ForEach_PosRecord;
    SplitCurrent  : WORD;
    DidAll        : BOOLEAN;
    MsgHeader     : FidoStoredHeader;
    Temp          : STRING;
    IORes         : BYTE;
    SubjectLine   : STRING[MaxLenSubj_F]; { ex. #0 }
    DT            : Dos.DateTime;
    Nop           : ValNop;
    Lp            : BYTE;

BEGIN
     IF (Msg.Date_F = '') THEN
        LogMessage (liReport,'[Import*.MSG] Detected missing date!');

     Target_Directory:=DeleteFrontAndBackSpaces (Target_Directory);

     IF (Target_Directory[Length (Target_Directory)] <> '\') THEN
        Target_Directory:=Target_Directory+'\';

     UpdateWriteFile (Target_Directory,0);

     AttachedFiles:='';
     IF DecodeFiles THEN
        DecodeAttachedFiles (DecodePath,MsgImport_AttachFile);

     EstimateSplitParts;

     MsgsLimited_Init (PosRec,{IncludeAttachments}(NOT DecodeFiles));

     SplitCurrent:=0;
     REPEAT
           Inc (SplitCurrent);

           { Vul de doel file aan met het eerst volgende bericht nummer }
           FidoMsgSave_OutName:=Target_Directory+
                                FidoMsgGetNextMsgNum (Target_Directory)+
                                '.MSG';

           { Schrijf het bericht naar disk }
           Assign (FidoMsgSave_OutFile,FidoMsgSave_OutName);
           {$I-} ReWrite (FidoMsgSave_Outfile,1); {$I+} IORes:=IOResult;
           IF (IORes <> 0) THEN
           BEGIN
                LogDiskIOError (IORes,'Error creating '+FidoMsgSave_OutName+'; aborting!');
                Break; { from the repeat/until }
           END;

           {$IFDEF LogFileIO}PostOpenF (FidoMsgSave_OutFile);{$ENDIF}

           IF Config.LogDebug THEN
              LogExtraMessage ('  Creating '+FidoMsgSave_OutName);

           UpdateInfoNr (INFO_MsgSave_Msgs,1);

           IF (Msg.Ready_F IN [Netmail,Local_Netmail]) THEN
              UpdateInfoNr (INFO_MsgSave_Net,1)
           ELSE
               UpdateInfoNr (INFO_MsgSave_Echo,1);

           IF PackBuf_Init (FidoMsgSave_Flush,lttCR,NIL) THEN
           BEGIN
                { Is dit bericht in meerdere delen opgesplitst? }
                { zoja, pas dan de Subject lijn aan en voeg een }
                { Split kludge toe.                             }

                IF (AttachedFiles <> '') THEN
                   {## for all split parts??}
                   SubjectLine:=AttachedFiles
                ELSE
                    SubjectLine:=Msg.Subj_F;

                {## this should be moved to the end (pga attachments) }
                IF (SplitParts > 1) THEN
                   SubjectLine:='('+Word2String (SplitCurrent)+
                                '/'+Word2String (SplitParts)+
                                ') '+SubjectLine;

                { vul het bericht header gedeelte met gegevens }

                { maak de header leeg, zodat er geen troep staat als je een }
                { hex dump van het bericht bekijkt.              RWI 951126 }
                FillChar (MsgHeader,SizeOf (FidoStoredHeader),0);

                WITH MsgHeader DO
                BEGIN
                     StrPCopy (FromUserName,Msg.FromUser_F);
                     StrPCopy (ToUserName,Msg.Stored_ToUser);
                     StrPCopy (Subject,SubjectLine);
                     StrPCopy (DateTime,Msg.Date_F);

                     TimesRead:=0;
                     Cost:=Msg.Cost_F;
                     ReplyTo:=0;
                     NextReply:=0;

                     Attribute:=Msg.Attr_F;

                     {## only if subject same for all parts }
                     IF (AttachedFiles <> '') THEN
                        Attribute:=Attribute OR MSGFILE;

                     WITH Msg.FromAddr_F DO
                     BEGIN
                          Overlap.origZone:=Zone;
                          origNet:=Net;
                          origNode:=Node;
                          Overlap.origPoint:=Point;
                     END; { with }

                     WITH Msg.Stored_ToAddr DO
                     BEGIN
                          Overlap.destZone:=Zone;
                          destNet:=Net;
                          destNode:=Node;
                          Overlap.destPoint:=Point;
                     END; { with }

                     IF Config.OpusDateFormat THEN
                     BEGIN
                          { speciale date format invullen }

                          WITH DT DO
                          BEGIN
                               Val (Copy (Msg.Date_F,1,2),Day,Nop);
                               Val (Copy (Msg.Date_F,8,2),Year,Nop);
                               Val (Copy (Msg.Date_F,12,2),Hour,Nop);
                               Val (Copy (Msg.Date_F,15,2),Min,Nop);
                               Val (Copy (Msg.Date_F,18,2),Sec,Nop);
                          END; { with }

                          DT.Month:=1;

                          FOR Lp:=1 TO 12 DO
                              IF (Month[Lp] = Copy (Msg.Date_F,4,3)) THEN
                              BEGIN
                                   DT.Month:=Lp;
                                   Break;
                              END;

                          IF (DT.Year > 79) THEN
                             Inc (DT.Year,1900)
                          ELSE
                              Inc (DT.Year,2000);

                          PackTime (DT,Overlap.DateWritten);

                          { swap byte order inside the longint }
                          Overlap.B1:=Overlap.A4;
                          Overlap.B2:=Overlap.A3;
                          Overlap.B3:=Overlap.A2;
                          Overlap.B4:=Overlap.A1;

                          { make both the same }
                          Overlap.DateWritten:=Overlap.DateArrived;
                     END; { if opus }

                END; { with }

                { write the binary header to the file }
                FidoMsgSave_Flush (MsgHeader,SizeOf (MsgHeader),NIL);

                { make sure we will not have a #0 in the body! }
                PackBuf_ReplaceNul ('!');

                { add AREA header for echomail }
                {not for *.MSG !!
                IF (Msg.Ready_F IN [Local_Echomail,Echomail]) THEN
                BEGIN
                     Temp:='AREA:'+AreaName+#13;
                     PackBuf_AddLine (Temp);
                END;
                }

                { write INTL, FMPT, TOPT for netmail }
                IF (Msg.Ready_F IN [Local_Netmail,Netmail]) THEN
                BEGIN
                     Temp:=#1'INTL '+Fido23DStr (Msg.Stored_ToAddr)+' '+
                                     Fido23DStr (Msg.FromAddr_F)+#13;
                     PackBuf_AddLine (Temp);

                     IF (Msg.Stored_ToAddr.Point <> 0) THEN
                     BEGIN
                          Temp:=#1'TOPT '+Word2String (Msg.Stored_ToAddr.Point)+#13;
                          PackBuf_AddLine (Temp);
                     END;

                     IF (Msg.FromAddr_F.Point <> 0) THEN
                     BEGIN
                          Temp:=#1'FMPT '+Word2String (Msg.FromAddr_F.Point)+#13;
                          PackBuf_AddLine (Temp);
                     END;
                END;

                { nu komen alle kludges, de header dus }
                FidoMsgSave_ReplaceMsgID:=(SplitCurrent > 1);
                MsgsForEach (Msg.HeaderTop_F,Import_AddHeaderLine);

                MsgsForEach (Msg.CopiedHeadersTop_F,Import_AddHeaderLine);

                { de split lijn komt NA de header }
                IF (SplitParts > 1) THEN
                BEGIN
                     Temp:=FidoCreateSplitLine (SplitCurrent,SplitParts)+#13;
                     PackBuf_AddLine (Temp);
                END;

                { nu een (gedeelte van) de body wegschrijven }
                DidAll:=MsgsLimited_ForEach (PosRec,SplitBodyLen,PackBuf_AddLine);

                {## todo: #13 #13 before tear-line test? }

                { nu de footer er nog achter. Hier staan dingen in als }
                { Origin line + Seenby's die in iedere kopie + Split   }
                { van het bericht moeten komen.                        }
                MsgsForEach (Msg.FooterTop_F,Import_AddFooterLine);

                PackBuf_ReplaceNul (#0); { disable replacement again }

                { write a terminating #0 to the file }
                Temp:=#0;
                PackBuf_AddLine (Temp);

                PackBuf_Done;

           END; { if PackBuf_Init success }

           { sluit de file voor dit split deel }
           {$IFDEF LogFileIO}PreCloseF (FidoMsgSave_OutFile);{$ENDIF}
           Close (FidoMsgSave_OutFile);
           FidoMsgSave_OutName:='';

     UNTIL DidAll;
END;


{--------------------------------------------------------------------------}
{ FidoClearMsgCount                                                        }
{                                                                          }
{ Deze procedure verwijderd de lijst met alle tellingen van *.MSG          }
{ directory's uit het geheugen.                                            }
{                                                                          }
{ Deze lijst is bedoeld om snel het volgende bericht nummer in een         }
{ *.MSG area te kunnen schrijven, zonder door het gehele bericht te        }
{ hoeven lopen.                                                            }
{                                                                          }
PROCEDURE FidoMsgClearMsgCount;

VAR Local : MsgCounterPtr;

BEGIN
     { RWI 951117: rewritten. CounterMsg was not set to NIL }
     WHILE (CounterMsg <> NIL) DO
     BEGIN
          Local:=CounterMsg;
          CounterMsg:=CounterMsg^.AreaNxt;

          FreeMem (Local,SizeOf (MsgCounter));
     END; { while }
END;


{--------------------------------------------------------------------------}
{ FidoInitMsgCount                                                         }
{                                                                          }
{ Deze procedure initialiseerd de lijst met tellingen van alle *.MSG       }
{ gebieden                                                                 }
{                                                                          }
PROCEDURE FidoMsgInitMsgCount;
BEGIN
     CounterMsg:=NIL;
END;


{--------------------------------------------------------------------------}
{ FidoGetNextMsgNum                                                        }
{                                                                          }
{ Zoekt het volgende bericht nummer bij een directory , beginnende bij 1   }
{ Van elke gegeven directory wordt gecontroleerd of het in de lijst in het }
{ geheugen zit.                                                            }
{                                                                          }
FUNCTION FidoMsgGetNextMsgNum (Path : STRING) : STRING;

VAR LastFound,
    LocalCnt       : MsgCounterPtr;
    PathId         : LONGINT;
    Error          : ValNop;
    ZoekRecord     : SearchRec;
    LaatstGevonden,
    HoogstGevonden : LONGINT;

BEGIN
     { Init van lokale variabelen                       }
     { Maak van de Areaname een CRC32 en stop die in    }
     { een tabeletje in het geheugen zodat we snel      }
     { door de huidige stand van zaken kunnen heenlopen }

     LastFound:=CounterMsg;
     LocalCnt:=CounterMsg;
     Path:=DeleteBackSpaces (Path);
     IF (Path[Length (Path)] <> '\') THEN
        Path:=Path+'\';
     PathId:=UpdateCRC32 (0,Path[1],Length (Path));

     { Zoeken in de tabel naar bekende directory's }
     WHILE (LocalCnt <> NIL) DO
     BEGIN
          { Als we een area gevonden hebben geef dan }
          { het volgende bericht nummer terug.       }
          IF (LocalCnt^.AreaID = PathID) THEN
          BEGIN
               { RWI 951117: controle toegevoegd die er voor zorgt dat }
               { WaterGate tegelijkertijd met een ander programma kan  }
               { draaien dat in dezelfde directory nummers gebruikt.   }
               { Vanaf het laatste gebruikte nummer wordt het eerst    }
               { volgende vrije nummer gezocht.                        }
               REPEAT
                     Inc (LocalCnt^.AreaCnt);
               UNTIL (NOT TestIfExist (Path+Longint2String (LocalCnt^.AreaCnt)+'.MSG'));

               FidoMsgGetNextMsgNum:=LongInt2String (LocalCnt^.AreaCnt);
               Exit;
          END;

          LastFound:=LocalCnt;
          LocalCnt:=LocalCnt^.AreaNxt;
     END; { while }

     { Niet gevonden }
     { LastFound wijst nu naar het laatste record }

     { Begin met tossen op 2.msg, zodat een 1.msg eventueel als }
     { high water mark gebruikt kan worden.                     }

     { Zoek nu alle files in de directory af en kijk of ze een hoger  }
     { nummer hebben. Bewaar dat hoogste nummer, tel er een bij op en }
     { geef het terug aan de aanroeper van het programma.             }

     HoogstGevonden:=0; { RWI 960604: was 1 -> resulteert in 2.msg }
     FindFirst (Path+'*.MSG',saJustFiles,ZoekRecord);

     WHILE (Dos.DosError = 0) DO
     BEGIN
          { converteer de naam naar een longint }
          Val (Copy (ZoekRecord.Name,1,Pos ('.',ZoekRecord.Name)-1),LaatstGevonden,Error);

          { kijk of deze file groter is dan de vorige }
          IF (Error = 0) AND (LaatstGevonden > HoogstGevonden) THEN
             HoogstGevonden:=LaatstGevonden;

          { volgende patient }
          FindNext (ZoekRecord);
     END; { while }

     FindClose (ZoekRecord);

     { een nieuw item aan de lijst toevoegen }
     GetMem (LocalCnt,SizeOf (MsgCounter){=12});
     {$IFDEF LogGetMem} LogGetMem (LocalCnt,SizeOf (MsgCounter),'LocalCnt'); {$ENDIF}
     PeekMem;

     WITH LocalCnt^ DO
     BEGIN
          AreaID:=PathId;
          AreaCnt:=HoogstGevonden+1;
          AreaNxt:=NIL;
     END; { with }

     { Link de variabele vast aan de lijst }
     IF (CounterMsg = NIL) THEN
        CounterMsg:=LocalCnt
     ELSE
         LastFound^.AreaNxt:=LocalCnt;

     FidoMsgGetNextMsgNum:=LongInt2String (LocalCnt^.AreaCnt);
END;


{$IFDEF WtrUtil}
{--------------------------------------------------------------------------}
{ FidoMsgImport                                                            }
{                                                                          }
{ Importeer berichten uit de *.MSG netmail area naar een Squish of Jam     }
{ base. Deze routine wordt gebruikt om berichten die in een lokale *.MSG   }
{ staan voor BBS programma's zichtbaar te maken.                           }
{                                                                          }
{ Wordt aangeroepen door de commandline optie 'IMPORT'                     }
{                                                                          }
{ IMPORT <AreaName> [<Aka>] [<-NOKILL>]                                    }
{                                                                          }
{ BTW. Mocht het je nog niet zijn opgevallen.. de onderstaande code is     }
{      een puinzooi, maar het werkt :-(                                    }
{                                                                          }
PROCEDURE FidoMsgImport (AreaName,Aka : STRING; ForceNoKill,DeskTop : BOOLEAN);

    PROCEDURE ErrorBeep;
    BEGIN
         {$IFDEF PLATFORM_OS2}
         DosBeep (220,200);
         {$ENDIF}

         {$IFDEF PLATFORM_WIN32}
         {## fix Win32 sound}
         {$ENDIF}

         {$IFDEF PLATFORM_DOS_ALL}
         Sound (220);        { Beep }
         Delay (200);        { For 200 ms }
         NoSound;            { Relief! }
         {$ENDIF}

         Delay (2000);
    END;

    PROCEDURE DeskErr (Msg : STRING);
    BEGIN
         IF Desktop THEN
            Error (Msg)
         ELSE
             LogExtraMessage (Msg);
    END;

VAR AreaRec       : AreaBaseRecordNrType;
    Address       : FidoAddrType;
    ZoekFile      : SearchRec;
    FidoMsgHeader : FidoStoredHeader;
    TotalMsgs     : LONGINT;
    UserName,
    Regel,
    LastRegel     : STRING;
    Fout          : ValNop;
    Test          : INTEGER;
    InputFile     : FBufferType;
    IORes         : BYTE;

LABEL FindNextMessage,
      CloseAndFindNextMessage;

BEGIN
     LogMessage (liTrivial,'Importing netmail messages from Fido *.MSG base');

     { Kijk of we uberhaupt wel een *.MSG netmail base hebben }
     IF (Config.FidoNetmailType <> FidoMsgType) THEN
     BEGIN
          DeskErr ('The system netmail area must be of *.MSG type to use this option!');
          ErrorBeep;
          Exit;
     END;

     { kijk of er een geldige areaname meegegeven is }
     AreaName:=UpCaseString (DeleteBackSpaces (AreaName));
     AreaRec:=GetAreaBaseRecordNrByAreaName (AreaName);
     IF (AreaRec = NILRecordNr) THEN
     BEGIN
          DeskErr ('Unknown or missing destination area name! '+AreaName);
          ErrorBeep;
          Exit;
     END;

     { lees het area record in }
     ReadAreaBaseRecord (AreaRec,AreaData);

     IF NOT (AreaData.FidoMsgStyle IN [SquishType,JAMType{,WildCatType}]) THEN
     BEGIN
          {DeskErr ('Unsupported target base type! Must be JAM, Squish or WildCat');}
          DeskErr ('Unsupported target base type! Must be JAM or Squish');
          ErrorBeep;
          Exit;
     END;

     { Kijk of een er een AKA meegegeven is, zoja, kijk of het een geldig }
     { AKA is.                                                            }
     Aka:=UpCaseString (DeleteBackSpaces (Aka));
     TotalMsgs:=0;
     FidoSplit ('0',Address);

     IF (Aka <> '') THEN
     BEGIN
          FidoSplit (AKA,Address);
          IF (NOT FidoOurAdres (Address)) THEN
          BEGIN
               DeskErr ('This address is not defined as one of our system AKAs!');
               ErrorBeep;
               Exit;
          END;
     END;

     {=====================================================================}

     { kijk of de gegeven directory wel bestaat }
     Regel:=Config.FidoNetmailPath;
     Dec (Regel[0]);

     FindFirst (Regel,saDirAndFiles,Zoekfile);
     IF (Dos.DosError <> 0) THEN
     BEGIN
          DeskErr ('Directory '+Config.FidoNetmailPath+' does not exist!');
          ErrorBeep;
          FindClose (ZoekFile);
          Exit;
     END;

     FindClose (ZoekFile);

     IF Desktop THEN
        Message ('Importing Netmail messages into '+AreaName);

     TotalMsgs:=0;

     { zoek naar het eerste *.MSG bestand in deze directory }
     FindFirst (Config.FidoNetmailPath+'*.MSG',saJustFiles,ZoekFile);

     { doorloop de directory tot alle berichten zijn gevonden }
     WHILE (Dos.DosError = 0) DO
     BEGIN
          { controleer of het bericht begint met een decimale naam }
          Val (Copy (Zoekfile.Name,1,Pos ('.',Zoekfile.Name)-1),Test,Fout);

          { zo niet, raporteer dit aan de bevoegde instanties }
          IF (Fout <> 0) THEN
          BEGIN
               LogExtraMessage ('Ignoring invalid name '+ZoekFile.Name);
               GOTO FindNextMessage;
          END;

          IF ((Zoekfile.Attr AND 1{readonly}) <> 0) THEN
          BEGIN
               LogMessage (liGeneral,'Skipping '+ZoekFile.Name+' (locked message)');
               GOTO FindNextMessage;
          END;

          { probeer het bericht te openen }
          IF (NOT FBufferOpen (InputFile,Config.FidoNetmailPath+ZoekFile.Name,MsgCacheSize,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               LogMessage (liFatal,'Failed to open '+Zoekfile.Name);
               GOTO CloseAndFindNextMessage;
          END;

          { probeer de header in te lezen }
          IF (NOT FBBlockRead (InputFile,FidoMsgHeader,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               LogMessage (liFatal,'Unable to read from '+Zoekfile.Name);
               GOTO CloseAndFindNextMessage;
          END;

          { maak eerst de interne bericht structuur leeg }
          MsgsEmpty;

          { vul dan opnieuw de header in }
          WITH FidoMsgHeader,Msg DO
          BEGIN
               Ready_F:=Local_Netmail;

               FromUser_F:=DeleteBackSpaces (StrPas (FromUserName));
               Stored_ToUser:=DeleteBackSpaces (StrPas (ToUserName));
               Subj_F:=DeleteBackSpaces (StrPas (Subject));
               Date_F:=FidoCorrectDate (DateTime);
               Cost_F:=Cost;
               Attr_F:=Attribute;

               { Let op ! Over het algemeen zetten alle editors rotzooi in }
               { de zone + point velden. Als er een zone in het bericht    }
               { staat halen we hem wel uit de MSGID ofzo.                 }

               WITH FromAddr_F DO
               BEGIN
                    Zone:=0;
                    Net:=origNet;
                    Node:=origNode;
                    Point:=0;
               END; { with }

               WITH Stored_ToAddr DO
               BEGIN
                    Zone:=0;
                    Net:=destNet;
                    Node:=destNode;
                    Point:=0;
               END; { with }
          END; { with }

          IF (Msg.FromUser_F = 'ARCmail') THEN
          BEGIN
               IF Config.LogDebug THEN
                  LogMessage (liGeneral,'Skipping '+Zoekfile.Name+' (from ARCmail)');

               GOTO CloseAndFindNextMessage;
          END;

          IF Config.LogDebug THEN
             LogMessage (liDebug,'Import: From='+Word2String (Msg.FromAddr_F.Net)+'/'+Word2String (Msg.FromAddr_F.Node)+
                         ', To='+Word2String (Msg.Stored_ToAddr.Net)+'/'+Word2String (Msg.Stored_ToAddr.Node));

          { loop door het hele bericht regel voor regel heen }
          WHILE FBReadLnCR (InputFile,Regel) AND (Regel <> #0) DO
          BEGIN
               { RWI 960425: overgenomen }

               { soft CR's strippen }
               WHILE (Pos (#$8D,Regel) > 0) DO
                     Delete (Regel,Pos (#$8D,Regel),1);

               FidoAddLineToMessage (Regel,LastRegel);
          END; { while }

          FidoAddLastLine (LastRegel);

          { we no longer need the FBuffer cache, so we disable it }
          FBufferFreeCache (InputFile);

          { Als de FROM zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de Area AKA                                     }
          IF (Msg.FromAddr_F.Zone = 0) THEN
             FidoMergeAdres (Config.NodeNrs[1],Msg.FromAddr_F);

          { Als de TO zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de FROM zone.                                 }
          IF (Msg.Stored_ToAddr.Zone = 0) AND (Msg.FromAddr_F.Zone <> 0) THEN
             Msg.Stored_ToAddr.Zone:=Msg.FromAddr_F.Zone;

          { Verwerk het bericht alleen als het aan ons systeem gericht is }
          { en niet voor een listserver, areafix of ander gedrocht.       }

          { Controleer op de AKA waarvoor we willen importeren }
          IF NOT ( ((Address.Zone <> 0) AND FidoCompare (Address,Msg.Stored_ToAddr)) OR
                   ((Address.Zone =  0) AND FidoOurAdres (Msg.Stored_ToAddr))) THEN
          BEGIN
               GOTO CloseAndFindNextMessage;
          END;

          UserName:=UpCaseString (Msg.Stored_ToUser);

          IF (UserName = UpCaseString (Config.GatewayUser)) OR
             (ListServerSearchName (UserName) <> NILPos) OR
             (UserName = ListServer1) OR
             (UserName = ListServer2) OR
             IsAreaFixName (UserName) OR
             IsCustomSkipName (UserName) OR
             (Config.FidoAcceptTO AND ((Pos ('@',UserName) > 0) OR (Pos ('!',UserName) > 0))) THEN
          BEGIN
               GOTO CloseAndFindNextMessage;
          END;

          {----------------------------------------------------------------------}
          { En hier deden we het dus voor, kijk naar welke message base het moet }

          Inc (TotalMsgs);

          { strip the local flag on all imported netmail, to prevent exporting }
          Msg.Attr_F:=Msg.Attr_F AND ($FFFF-MSGLOCAL);

          CASE AreaData.FidoMsgStyle OF
               JamType :
                   { note: assume files have been decoded already }
                   Jam_ImportMessage (AreaData.AreaName_F,AreaData.FidoMsgPath,'',FALSE);

               SquishType :
                   Squish_ImportMessage (AreaData.AreaName_F,AreaData.FidoMsgPath,'',FALSE);

               {WildCatType:
                   WildCatMsgBase.WriteMessage (AreaData.AreaName_F,AreaData.FidoMsgPath);

               PCBoardType :
                  PCBoardMsgBase.WriteMessage{(Msg,AreaName,AreaData.FidoMsgPath);}
          END; { case }

          FBufferClose (InputFile);

          { Als we de kill vlag gebruiken wordt het bericht na de import }
          { verwijderd uit de *.MSG directory.                           }
          IF (NOT ForceNoKill) THEN
          BEGIN
               {$I-} Erase (InputFile.Bestand); {$I+} IORes:=IOResult;
               IF (IORes <> 0) THEN
                  LogDiskIOError (IORes,'[FidoMsgImport] Unable to delete '+InputFile.Filename);
          END;

          GOTO FindNextMessage;

CloseAndFindNextMessage:

          FBufferClose (InputFile);

FindNextMessage:

          FindNext (ZoekFile);
     END; { while DosError == 0  }

     FindClose (ZoekFile);

     { RWI 960425: Fix: close the last used bases }
     Squish_Done;
     Jam_Done;

     LogExtraMessage ('Imported '+Longint2String (TotalMsgs)+' messages.');

     IF Desktop THEN
        WindowPop; { message }

     MsgsEmpty;
END;
{$ENDIF (WtrUtil)}


{--------------------------------------------------------------------------}
{ FidoMsg_Rescan                                                           }
{                                                                          }
{ This routine performs a re-scan of an area.                              }
{                                                                          }
PROCEDURE FidoMsg_Rescan (VAR AreaData : AreaBaseRecord);

VAR ZoekFile      : SearchRec;
    InputFile     : FBufferType;
    FidoMsgHeader : FidoStoredHeader;
    IORes         : BYTE;
    MsgNr         : LONGINT;
    Error         : ValNop;
    DirectoryName,
    Regel,
    LastRegel     : STRING;
    Result        : RescanResultType;
    DT            : Dos.DateTime;

LABEL FindNextMsg;

BEGIN
     IF (AreaData.FidoMsgPath = '') THEN
     BEGIN
          LogMessage (liConfig,'[Rescan] Path not defined for *.MSG area '+AreaData.AreaName_F);
          Exit;
     END;

     { houdt de stats bij van de lokale gebieden }
     UserDataRecNr:=NILRecordNr;
     DirectoryName:=AreaData.FidoMsgPath;

     { verwijder backspace aan het einde }
     IF (DirectoryName[Length (DirectoryName)] = '\') THEN
        Delete (DirectoryName,Length (DirectoryName),1);

     { kijk of de gegeven directory wel bestaat }
     FindFirst (DirectoryName,saDirAndFiles,Zoekfile);
     IF (Dos.DosError <> 0) THEN
     BEGIN
          LogMessage (liConfig,'Directory '+DirectoryName+' does not exist!');
          FindClose (ZoekFile);
          Exit;
     END;
     FindClose (ZoekFile);

     { zoek naar het eerste *.MSG bestand in deze directory }
     DirectoryName:=AreaData.FidoMsgPath;
     IF (DirectoryName[Length (DirectoryName)] <> '\') THEN
        DirectoryName:=DirectoryName+'\';

     FindFirst (DirectoryName+'*.MSG',saDirAndFiles,ZoekFile);
     IF (Dos.DosError = 18) THEN
     BEGIN
          FindClose (ZoekFile);
          Exit; { geen files }
     END;

     Result:=rstNoExport;

     { doorloop de directory tot alle berichten zijn gevonden }
     WHILE (NOT GlobalAbort) AND (Dos.DosError = 0) AND (Result <> rstNoExport_Stop) DO
     BEGIN
          { controleer of het bericht begint met een decimale naam }
          Val (Copy (Zoekfile.Name,1,Pos ('.',Zoekfile.Name)-1),MsgNr,Error);

          { zo niet, raporteer dit aan de bevoegde instanties }
          IF (Error > 0) THEN
          BEGIN
               LogExtraMessage ('Ignoring invalid number in *.MSG filename '+ZoekFile.Name);
               GOTO FindNextMsg;
          END;

          IF ((Zoekfile.Attr AND 1{read-only}) <> 0) THEN
             GOTO FindNextMsg;

          Slice_Now;

          IF KeyPressed AND (Ramon.ReadKey = kEsc) THEN
          BEGIN
               GlobalAbort:=TRUE;
               Break;
          END;

          UpdateReadFile (DirectoryName+Zoekfile.Name,Zoekfile.Size);

          { probeer het bericht te openen }
          IF (NOT FBufferOpen (InputFile,DirectoryName+Zoekfile.Name,MsgCacheSize,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               { RWI 961005: added FBufferOpen result check, log and Continue (!!) }
               LogMessage (liFatal,'Failed to open '+Zoekfile.Name);
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { probeer de header in te lezen }
          IF (NOT FBBlockRead (InputFile,FidoMsgHeader,SizeOf (FidoStoredHeader))) THEN
          BEGIN
               LogMessage (liFatal,'Unable to read from '+Zoekfile.Name);
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          IF ((FidoMsgHeader.Attribute AND MSGFRQ) <> 0) OR
             ((FidoMsgHeader.Attribute AND MSGHOLD) <> 0) THEN
          BEGIN
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          FidoDateTimeStr2DosDateTime (FidoCorrectDate (FidoMsgHeader.DateTime),DT);
          Result:=Rescan_ExportCheck (DosDateTime2UnixDateTime (DT));

          LastRegel:='';

          Found_Path:=FALSE;
          Found_SeenBy:=FALSE;
          Found_Tear:=FALSE;
          Found_Origin:=FALSE;

          MsgsEmpty;

          Msg.Ready_F:=Local_Echomail;
          Msg.Area_F:=AreaData.AreaName_F;

          Msg.FromUser_F:=DeleteBackSpaces (StrPas (FidoMsgHeader.FromUserName));
          Msg.Stored_ToUser:=DeleteBackSpaces (StrPas (FidoMsgHeader.ToUserName));
          Msg.Subj_F:=DeleteBackSpaces (StrPas (FidoMsgHeader.Subject));
          Msg.Date_F:=FidoCorrectDate (FidoMsgHeader.DateTime);
          Msg.Cost_F:=FidoMsgHeader.Cost;
          Msg.Attr_F:=FidoMsgHeader.Attribute;

          { Let op ! Over het algemeen zetten alle editors rotzooi }
          { in de zone + point velden. Als er een zone in het      }
          { bericht staat halen we hem wel uit de MSGID ofzo.      }

          { FrontDoor/Opus zetten in die velden twee datums }

          Msg.FromAddr_F.Zone:=0;
          Msg.FromAddr_F.Net:=FidoMsgHeader.origNet;
          Msg.FromAddr_F.Node:=FidoMsgHeader.origNode;
          Msg.FromAddr_F.Point:=0;

          Msg.Stored_ToAddr.Zone:=0;
          Msg.Stored_ToAddr.Net:=FidoMsgHeader.destNet;
          Msg.Stored_ToAddr.Node:=FidoMsgHeader.destNode;
          Msg.Stored_ToAddr.Point:=0;

          WHILE FBReadLnCR (InputFile,Regel) AND (Regel <> #0) DO
          BEGIN
               { soft CR's strippen }
               WHILE (Pos (#$8D,Regel) > 0) DO
                     Delete (Regel,Pos (#$8D,Regel),1);

               FidoAddLineToMessage (Regel,LastRegel);
          END; { while }

          FidoAddLastLine (LastRegel);

          { ignore LOcKed messages }
          IF ((Msg.ExtAttr_F AND EXTMSGLOK) <> 0) THEN
          BEGIN
               FBufferClose (InputFile);
               GOTO FindNextMsg;
          END;

          { we no longer need the FBuffer cache, so we disable it }
          FBufferFreeCache (InputFile);

          { Als de FROM zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de Area AKA                                     }
          IF (Msg.FromAddr_F.Zone = 0) THEN
             IF (Msg.Ready_F = Local_Echomail) THEN
                FidoMergeAdres (Config.NodeNrs[AreaData.OriginAka],Msg.FromAddr_F)
             ELSE
                 {## check MSGID?}
                 FidoMergeAdres (Config.NodeNrs[1],Msg.FromAddr_F);

          { Als de TO zone nog steeds nul is, probeer hem dan aan te }
          { vullen met de FROM zone.                                 }
          IF (Msg.Stored_ToAddr.Zone = 0) THEN
             Msg.Stored_ToAddr.Zone:=Msg.FromAddr_F.Zone;

          { verwijderen van lokale vlaggen van een bericht }
          Msg.Attr_F:=Msg.Attr_F AND ($FFFF-MSGLOCAL-MSGXX2);

          FidoFinishEchomailExport (AreaData);

          Rescan_DeliverMessage;

 FindNextMsg:
          FindNext (Zoekfile);
     END; { while DosError == 0 }

     FindClose (ZoekFile);
     MsgsEmpty;
END;


END.
