UNIT ImpExp;

{$i platform.inc}

{ Routines om configuratie databases van andere systemen in te lezen }

{ History:

RvdW 20-02-93 Begonnen met deze unit, GEcho Exported Files routines.
     20-02-93 Uitbreiding: ImportGEchoAreaFile om area te importeren.
     23-02-93 Uitbreiding: ImportGEchoNodeFIle om nodes te importeren.
     26-02-93 ImportGEchoAreaFile uitgebreid met ConnectArea om de users
              ook daadwerkelijk aan te kunnen sluiten.
     20-03-93 Uitbreidingen om ook de Waffle Systems file en UUCico Feeds
              file in te kunnen lezen.
     30-03-93 Aanpassing invullen IsInGroups bij importeren AREAFILE.GE.
              De P_ areas zaten in group P t/m Z, ipv alleen in P. Bleek
              een Longint-shl foutje.
     31-03-93 UseNet UUCPName wordt nu niet meer in UpperCase geforceerd.
     31-03-93 Newsgroups kunnen nu ook geimporteerd worden.
MD   04-08-93 Importeren van Squish configuratie bestanden
              voorlopig alleen area informatie
              Nu ook exporteren, voorlopig maar gewoon in de Import unit
     26-11-93 Fixes + Uitbreidingen in de Import Waffle Usenet file
     25-01-94 '%' & '#' worden nu als rem regels in de feeds file gezien
     12-02-94 Import zou nu compatbile moeten zijn met Gecho 1.02
     15-04-94 Met hulp van T.De graaff Gecho 1.02 fixes eindelijk rond
              gekregen, GvdLand documenteerd zijn veranderingen blijkbaar
              niet goed genoeg.
     05-07-94 Exporteer config op grote school
}

INTERFACE

PROCEDURE ImportExportMenu;

PROCEDURE ExportAREASBBS (Param : STRING);
PROCEDURE ExportSquishConfig (Param : STRING);


IMPLEMENTATION

USES Ramon,
     Msgs,
     Database,
     Globals,
     AreaBase,
     UserBase,
     AreaMgr,
     Fido,
     Strings,
     Logs,
     Cfg,
     Slice;

{$I wtrhlp.inc}

VAR Path     : STRING[79];
    PathType : BYTE;
    Desktop  : BOOLEAN;

{--------------------------------------------------------------------------}
{ GetItem                                                                  }
{                                                                          }
{ Plukt steeds het volgende sleutel woord uit een string.                  }
{                                                                          }
PROCEDURE GetItem (VAR Invoer,Item : STRING);
BEGIN
     Invoer:=DeleteFrontSpaces (Invoer);
     Item:=Copy (Invoer,1,Pos (' ',Invoer)-1);

     IF (Item = '') THEN
     BEGIN
          Item:=Invoer;
          Invoer:='';
     END ELSE
         Invoer:=Copy (Invoer,Length (Item)+1,255);
END;


{--------------------------------------------------------------------------}
{ EnterImportFilename                                                      }
{                                                                          }
{ Deze routine vraagt om de naam van de te importeren file. Het volledige  }
{ pad kan ingevoerd worden.                                                }
{                                                                          }
{ Boolean , FALSE = Export , TRUE = Import                                 }
{                                                                          }
PROCEDURE EnterImportFilename (FileType : BOOLEAN);

CONST Xb = 9;
      Yb = 17;
      Xl = 64;
      Yl = 6;

VAR Quit : BOOLEAN;
    Hulp : STRING[2];

BEGIN
     WindowPush (Xb,Yb,Xl,Yl);
     BoxDraw (Double,Xb,Yb,Xl,Yl);

     IF FileType THEN
        Hulp:='im'
     ELSE
         Hulp:='ex';

     WriteXY (Xb+2,Yb+1,'Filename and path of file to '+Hulp+'port (F3 to pick file)');

     FieldInit;
     FieldDefineFileMgr (1,Xb+2,Yb+3,79,60,0,0,@Path,AnyFileMgr,FALSE);
     FieldSetHelp (1,htr_ImpExp_Filename);

     PushKeysLine;
     WriteFieldEditDirectKeysLine;

     Quit:=FALSE;
     REPEAT
           FieldEditDirect;

           Quit:=TRUE;
           IF (Key = kRet) AND
              (NOT TestIfExist (Path)) AND FILETYPE THEN
           BEGIN
                Error ('File does not exist');
                Quit:=FALSE;
           END;
     UNTIL Quit;

     PopKeysLine;
     WindowPop; { path window }
END;


{--------------------------------------------------------------------------}
{ EnterAndImport                                                           }
{                                                                          }
{ Deze routine vraagt om een filenaam in de Path variabelen en roept als   }
{ dat gelukt is de ReadXXXX routine aan.                                   }
{                                                                          }
TYPE ProcType = PROCEDURE;

PROCEDURE EnterAndImport (FileType : BOOLEAN; DefaultPath : STRING; ProcName : ProcType; NewPathType : BYTE);

VAR Quit : BOOLEAN;

BEGIN
     IF (PathType <> NewPathType) THEN
     BEGIN
          Path:=DefaultPath;
          PathType:=NewPathType;
     END;

     Path:=AddUpWithSpaces (79,Path);

     Quit:=FALSE;
     REPEAT
           EnterImportFilename (FileType);

           CASE Key OF
                kEsc : Quit:=TRUE;

                kRet : BEGIN
                            Path:=DeleteFrontAndBackSpaces (Path);
                            ProcName;
                            Quit:=TRUE;
                       END;
           END; { case }
     UNTIL Quit;
END;


{--------------------------------------------------------------------------}
{ ReadFastEchoConfig                                                       }
{                                                                          }
{--------------------------------------------------------------------------}
{ ReadFastEchoNodes                                                        }
{                                                                          }
PROCEDURE ReadFastEchoConfig (TypeCode : BYTE; TypeDesc : STRING);

CONST FE_MAXAREAS = 3072;

TYPE FEConfigRecord = RECORD
                            revision        : WORD;
                            flags           : LONGINT;
                            NodeCnt,
                            AreaCnt,
                            unused1         : WORD;
                            NetMPath,
                            MsgBase,
                            InBound,
                            OutBound,
                            Unpacker,
                            LogFile         : ARRAY[1..56] OF CHAR;
                            unused2         : ARRAY[1..336] OF BYTE;
                            Unpacker2,
                            UnprotInBound,
                            StatFile,
                            SwapPath,
                            SemaphorePath,
                            BBSConfigPath,
                            QueuePath       : ARRAY[1..56] OF CHAR;
                            unused3         : ARRAY[1..32] OF BYTE;
                            RetearTo        : ARRAY[1..40] OF BYTE;
                            LocalInBound    : ARRAY[1..56] OF CHAR;
                            ExtAfter,
                            ExtBefore       : ARRAY[1..52] OF CHAR;
                            Unused4         : ARRAY[1..480] of BYTE;
                            CC              : ARRAY[1..10,1..34] of BYTE;
                            security,
                            loglevel         : BYTE;
                            def_days,
                            def_messages     : WORD;
                            unused5          : ARRAY[1..462] of BYTE;
                            autorenum,
                            def_recvdays     : WORD;
                            openQQQs,
                            Swapping         : BYTE;
                            compressafter,
                            afixmaxmsglen,
                            compressfree     : WORD;
                            TempPath         : ARRAY[1..56] OF CHAR;
                            graphics,
                            BBSSoftware      : BYTE;
                            AreaFixHelp      : ARRAY[1..56] OF CHAR;
                            unused6          : ARRAY[1..504] of BYTE;
                            AreaFixFlags     : WORD;
                            QuietLevel,
                            Buffers,
                            FWACnt,                     { # of ForwardAreaFix records}
                            GDCnt            : BYTE;    { # of Group Default records }
                            rescan_def       : ARRAY[1..5] OF WORD;
                            duperecords      : LONGINT;
                            arcext           : WORD;
                            AFixRcptLen      : WORD;
                            AkaCnt,
                            resv             : BYTE;              { # of Aka records stored }
                            maxPKT           : WORD;
                            sharing,
                            sorting          : Byte;
                            sysops           : Array[1..11,1..40] of BYTE;
                            AreaFixLog,
                            TempInBound      : ARRAY[1..56] OF CHAR;
                            maxPKTmsgs,
                            RouteCnt              : WORD;       { # of PackRoute records }
                            maxPACKratio          : Byte;
                            SemaphoreTimer        : Byte;
                            PackerCnt,
                            UnpackerCnt,                        { # of Packers and Unpackers records }
                            GroupCnt,
                            OriginCnt             : Byte;       { # of GroupNames and Origin records }
                            mailer                : Word;
                            maxarcsize,maxarcdays : Word;
                            reserved              : ARRAY[1..806] OF BYTE;
                            AreaRecSize,
                            GrpDefRecSize,                      { Size  of  Area  and  GroupDefaults }
                            MaxAreas,                           { records stored in this file        }
                            MaxNodes,                           { Current max values for this config }
                            NodeRecSize           : Word;       { Size of each stored Node record    }
                            offset                : Longint;    { This is the offset from the current}
                      END;                                      { file-pointer to the 1st Node       }
(*
TYPE FEExtensionHeader = RECORD
                               Typ    : WORD;    { EH_...                           }
                               Offset : LONGINT; { length of field excluding header }
                         END;
*)

TYPE Address = RECORD
                     zone,
                     net,
                     node,
                     point : WORD;
               END;

TYPE FENodeRecord = RECORD
                          addr,
                          arcdest      : Address;
                          aka,
                          autopassive,
                          newgroup,
                          resv1        : BYTE;
                          flagsByte1   : BYTE;
                          flagsByte2   : BYTE;
                          flagsByte3   : BYTE;
                          afixflags    : WORD;
                          resv2        : WORD;
                          Password     : ARRAY[1..9] OF BYTE;
                          AreafixPW    : ARRAY[1..9] OF BYTE;
                          sec_level    : WORD;
                          Groups       : ARRAY[0..3] OF BYTE;
                          resv3        : LONGINT;
                          resv4,
                          maxarcsize   : WORD;
                          SysOpName    : ARRAY[1..36] OF CHAR;
                          Areas        : ARRAY[1..FE_MAXAREAS DIV 8] OF BYTE;
                                                     { Bit-field with CONFIG.MaxAreas / 8    }
                                                     { bits, Byte 0/Bit 7 is conference #0   }
                                                     { Total size of each record is stored   }
                                                     { in CONFIG.NodeRecSize                 }
                    END;

TYPE FEAreaRecord = RECORD
                          NAME             : ARRAY[1..52] OF CHAR;
                          board,
                          conference,
                          read_sec,
                          write_sec        : Word;
                          Info             : Word;
                          flags            : Word;
                          advflags         : Word;
                          resv1            : Word;
                          seenbys,
                          resv2            : LongInt;
                          days,
                          messages,
                          recvdays         : Word;
                          path             : ARRAY[1..56] OF CHAR;
                          desc             : ARRAY[1..52] OF CHAR;
                    END;

TYPE AreaMapArray = ARRAY[0..FE_MAXAREAS-1] OF AreaBaseRecordNrType;
     { maps conference numbers to areabase record numbers }
     { used during user import.                           }

VAR FECfg      : FILE;
    IORes      : BYTE;
    FEConfig   : FEConfigRecord;
    SeekBase   : LONGINT;
    BytesRead  : WordLong;
    AreaMapPtr : ^AreaMapArray;


    {----------------------------------------------------------------------}
    { BuildAreaMap                                                         }
    {                                                                      }
    { Deze routine doorloopt alle areas in the fastecho config en zoekt de }
    { gelijke in de areabase. Record nummers worden opgeslagen en gebruikt }
    { tijdens het importeren van users, om de areas aan te sluiten.        }
    {                                                                      }
    PROCEDURE BuildAreaMap;

    VAR FEArea    : FEAreaRecord;
        AreaRecNr : AreaBaseRecordNrType;
        Lp        : WORD;

    BEGIN
         IF (AreaMapPtr <> NIL) THEN
            Exit;

         Message ('Building Conference to Area Definition map');

         GetMem (AreaMapPtr,SizeOf (AreaMapArray));
         FOR Lp:=0 TO FE_MAXAREAS-1 DO
             AreaMapPtr^[Lp]:=NILRecordNr;

         FOR Lp:=1 TO FEConfig.AreaCnt DO
         BEGIN
              Seek (FECfg,SizeOf (FEConfigRecord)+FEConfig.Offset+
                          Longint (FEConfig.NodeCnt)*FEConfig.NodeRecSize+
                          (Longint (Lp)-1)*FEConfig.AreaRecSize);

              { read area record }
              BlockRead (FECfg,FEArea,SizeOf (FEAreaRecord));

              IF (FEArea.Board = $8000) THEN
                 Continue; { delete }

              IF ((FEArea.Flags SHR 4) IN [3,4]) THEN
                 Continue; { dupe/bad }

              { check conference number }
              IF (FEArea.Conference >= FE_MAXAREAS) THEN
              BEGIN
                   ListAddItem ('Invalid conference number ('+Word2String (FEArea.Conference)+
                                ' for area '+Word2String (Lp),65535,Bottom);
                   Continue; { too bad }
              END;

              AreaMapPtr^[FEArea.Conference]:=GetAreaBaseRecordNrByAreaName_F (UpCaseString (StrPas (@FEArea.Name)));
         END;

         WindowPop;
    END;


    {----------------------------------------------------------------------}
    { ImportFENodes                                                        }
    {                                                                      }
    { Deze routine importeert FastEcho nodes. File is open en file pointer }
    { staat goed.                                                          }
    {                                                                      }
    PROCEDURE ImportFENodes;

    VAR Lp               : WORD;
        FENode           : FENodeRecord;
        UserBaseRecordNr : UserBaseRecordNrType;
        GL               : GroupNrType;
        G1,G2            : BYTE;
        ConferenceNr     : WORD;
        AreaLp           : WORD;
        ConnectCount,
        FailedCount      : WORD;

    BEGIN
         BuildAreaMap;

         {$I-} Seek (FECfg,SeekBase); {$I+} IORes:=IOResult;
         IF (IORes <> 0) THEN
         BEGIN
              ListAddItem  ('Error seeking to start of nodes (error '+Byte2String (IORes)+')',65535,Bottom);
              Exit
         END;

         Message ('Working...');

         FOR Lp:=1 TO FEConfig.NodeCnt DO
         BEGIN
              {$I-} BlockRead (FECfg,FENode,FEConfig.NodeRecSize,BytesRead); {$I+} IORes:=IOResult;
              IF (IORes <> 0) OR (BytesRead <> FEConfig.NodeRecSize) THEN
              BEGIN
                   ListAddItem ('Error reading node block '+Word2String (Lp),65535,Bottom);
                   Exit;
              END;

              EmptyUserDataRecord;

              WITH UserData DO
              BEGIN
                   System:=_F;

                   Address.Zone:=FENode.Addr.Zone;
                   Address.Net:=FENode.Addr.Net;
                   Address.Node:=FENode.Addr.Node;
                   Address.Point:=FENode.Addr.Point;
                   Address.Domain:='';

                   { controleer of user al bestaat ! }
                   IF FindUserBaseRecordByFidoAddress (UserData.Address,UserBaseRecordNr) THEN
                   BEGIN
                        ListAddItem ('User '+Fido2Str (UserData.Address)+' already exists',UserBaseRecordNr,Bottom);
                   END ELSE
                   BEGIN
                        UserBaseRecordNr:=UserBaseRecCount+1;
                        ListAddItem ('Adding user '+Fido2Str (UserData.Address),UserBaseRecordNr,Bottom);

                        ResetGroupFlags (Groups);
                        GL:=1;
                        FOR G1:=0 TO 3 DO
                            FOR G2:=7 DOWNTO 0 DO
                            BEGIN
                                 IF (FENode.Groups[G1] AND (1 SHL G2)) = 0 THEN
                                    AddGroupToGroupList (Groups,GL);

                                 Inc (GL);
                            END;

                        Sysop:=StrPas (@FENode.SysOpName);
                        AreaFixPwd:=StrPas (@FENode.AreafixPW);
                        PacketPwd:=StrPas (@FENode.Password);

                        Notify_F:=((FENode.FlagsByte3 AND 1) = 0); { bit 16/24 }
                        AllowCreate:=((FENode.FlagsByte1 AND $40) = $40); { bit 6/24 }

                        WriteUserBaseRecord (UserBaseRecordNr,UserData);
                   END;

                   { doorloop alle areas en sluit ze aan }
                   ConnectCount:=0;
                   FailedCount:=0;

                   ConferenceNr:=0;
                   FOR AreaLp:=1 TO (FEConfig.MaxAreas DIV 8) DO
                       FOR G2:=7 DOWNTO 0 DO
                       BEGIN
                            IF ((FENode.Areas[AreaLp] AND (1 SHL G2)) <> 0) THEN
                            BEGIN
                                 IF (AreaMapPtr^[ConferenceNr] <> NILRecordNr) THEN
                                 BEGIN
                                      ConnectArea (AreaMapPtr^[ConferenceNr],UserBaseRecordNr);
                                      Inc (ConnectCount);
                                 END ELSE
                                     Inc (FailedCount);
                            END;

                            Inc (ConferenceNr);
                       END;

                   IF (ConnectCount <> 0) THEN
                      ListAddItem ('    Connected '+Word2String (ConnectCount)+' area(s)',UserBaseRecordNr,Bottom);

                   IF (FailedCount <> 0) THEN
                      ListAddItem ('    Could not find '+Word2String (FailedCount)+' area(s)',UserBaseRecordNr,Bottom);

              END; { with }
         END; { for }

         WindowPop;
    END;


    {----------------------------------------------------------------------}
    { ImportFEAreas                                                        }
    {                                                                      }
    { Deze routine importeert FastEcho areas. File is open en file pointer }
    { staat goed.                                                          }
    {                                                                      }
    PROCEDURE ImportFEAreas;

    VAR Lp            : WORD;
        FEArea        : FEAreaRecord;
        AreaBaseRecNr : AreaBaseRecordNrType;
        Grp           : BYTE;

    BEGIN
         {$I-} Seek (FECfg,SeekBase); {$I+} IORes:=IOResult;
         IF (IORes <> 0) THEN
         BEGIN
              ListAddItem  ('Error seeking to start of areas ('+Byte2String (IORes)+')',65535,Bottom);
              Exit;
         END;

         Message ('Working...');

         FOR Lp:=1 TO FEConfig.AreaCnt DO
         BEGIN
              {$I-} BlockRead (FECfg,FEArea,SizeOf (FEAreaRecord),BytesRead); {$I+} IORes:=IOResult;
              IF (IORes <> 0) OR (BytesRead <> SizeOf (FEAreaRecord)) THEN
              BEGIN
                   ListAddItem ('Error reading area block '+Word2String (Lp),65535,Bottom);
                   Exit;
              END;

              IF (FEArea.Board = $8000) THEN
                 Continue; { deleted }

              IF ((FEArea.Flags AND $00F0) = $0030) THEN
              BEGIN
                   ListAddItem ('Skipping BAD area',0,Bottom);
                   Continue;
              END;

              IF ((FEArea.Flags AND $00F0) = $0040) THEN
              BEGIN
                   ListAddItem ('Skipping DUPE area',0,Bottom);
                   Continue;
              END;

              EmptyAreaDataRecord (AreaData);

              WITH AreaData DO
              BEGIN
                   AreaName_F:=UpCaseString (StrPas (@FEArea.Name));
                   AreaName_U:=AreaName_F;

                   AreaBaseRecNr:=GetAreaBaseRecordNrByAreaName_F (AreaData.AreaName_F);

                   IF (AreaBaseRecNr <> NILRecordNr) THEN
                   BEGIN
                        ListAddItem ('Area '+AreaData.AreaName_F+' already exists',AreaBaseRecNr,Bottom);
                        Continue;
                   END;

                   { take group byte and make 1..MaxGroups }
                   Grp:=1+(FEArea.Info SHR 8);
                   IF (Grp > MaxGroups) THEN
                      Grp:=1;

                   Comment:=StrPas (@FEArea.Desc);

                   ResetGroupFlags (IsInGroups);
                   AddGroupToGroupList (IsInGroups,Grp);

                   AreaBaseRecNr:=AreaBaseRecCount+1;
                   ListAddItem ('Created '+AreaData.AreaName_F+' in group '+BuildSingleGroupDesc (Grp),AreaBaseRecNr,Bottom);

                   CASE ((FEArea.Flags SHR 4) AND 15) OF
                        0 : AreaType:=Area_Echo;
                        1 : AreaType:=Area_Netmail;
                        2 : AreaType:=Area_Local;
                       {3 : badmail;}
                       {4 : dupeboard;}
                        ELSE BEGIN
                             ListAddItem ('    Unknown Area Type '+Byte2String (FEArea.Flags SHR 4)+
                                          '; setting to ECHO',65535,Bottom);
                             AreaType:=Area_Echo;
                        END;
                   END; { case }

                   IF (FEArea.Board = $4000) THEN
                   BEGIN
                        { not hmb, check for *.msg, squish, jam }
                        CASE (FEArea.Flags AND 15) OF
                             0: ListAddItem ('    QBBS type not supported, setting to NONE',65535,Bottom);
                             1: FidoMsgStyle:=FidoMsgType;
                             2: FidoMsgStyle:=SquishType;
                             3: FidoMsgStyle:=JamType;
                             7: {passthrough: keep at none};
                        END; { case }
                   END;

                   FidoMsgPath:=StrPas (@FEArea.Path);
                   FidoMsgAge:=FEArea.Days;
                   FidoMsgLimit:=FEArea.Messages;

                   WriteAreaBaseRecord (AreaBaseRecNr,AreaData);
              END; { with }
         END; { for }

         WindowPop;
    END;

VAR {FEExtHdr : FEExtensionHeader;}
    Quit     : BOOLEAN;
    Keuze    : WORD;

LABEL Abort;

BEGIN
     Assign (FECfg,Path);
     {$I-} Reset (FECfg,1); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open '+Path+' (error '+Byte2String (IORes)+')');
          Exit;
     END;

     ListDefine (2,3,Video.Cols-5,Video.Rows-4,Default,'Import '+TypeDesc+' from '+Path+' results',0);

     ReadAreaBaseIndexTable;
     ReadUserBaseIndexTable;

     AreaMapPtr:=NIL;

     {$I-} BlockRead (FECfg,FEConfig,SizeOf (FEConfigRecord),BytesRead); {$I+} IORes:=IOResult;
     IF (IORes <> 0) OR (BytesRead <> SizeOf (FEConfigRecord)) THEN
     BEGIN
          ListAddItem ('Error reading configuration block',65535,Bottom);
          GOTO Abort;
     END;

     IF (FEConfig.Revision <> 6) THEN
     BEGIN
          ListAddItem ('Revision ('+Byte2String (FEConfig.Revision)+') not supported',0,Bottom);
          GOTO Abort;
     END;

     (* works as documented, but not needed
     SeekBase:=SizeOf (FEConfigRecord);

     WHILE (FilePos (FECfg) < FEConfig.Offset) DO
     BEGIN
          BlockRead (FECfg,FEExtHdr,SizeOf (FEExtensionHeader),BytesRead);
          IF (BytesRead <> SizeOf (FEExtensionHeader)) THEN
          BEGIN
               ListAddItem ('Error reading extension block',65535,Bottom);
               GoTO Abort;
          END;

          ListAddItem ('Extension block '+Word2HexString (FEExtHdr.Typ)+', length '+Longint2String (FEExtHdr.Offset),0,Bottom);

          Seek (FECfg,FilePos (FECfg)+FEExtHdr.Offset);
     END;
     *)

     SeekBase:=SizeOf (FEConfigRecord)+FEConfig.Offset;

     IF (TypeCode = 1{nodes}) THEN
     BEGIN
          ImportFENodes;
     END ELSE
     BEGIN
          { adjust SeekBase to point behind the user record }
          SeekBase:=SeekBase+FEConfig.NodeCnt*FEConfig.NodeRecSize;
          ImportFEAreas;
     END;

Abort:
     Close (FECfg);

     IF (AreaMapPtr <> NIL) THEN
        FreeMem (AreaMapPtr,SizeOf (AreaMapArray));

     JunkAreaBaseIndexTable;
     JunkUserBaseIndexTable;

     ListAddItem ('',0,Bottom);
     ListAddItem ('Import done. Arrows to scroll, Esc=Done, Enter=Edit',59999,Bottom);
     ListSetCursorOnItem (59999);

     Quit:=FALSE;
     REPEAT
           Keuze:=ListSelect (NoTag,[]);

           CASE Key OF
                kEsc :
                     Quit:=TRUE;

                kRet :
                    IF (Keuze > 0) AND (Keuze < 59999) THEN
                    BEGIN
                         IF (TypeCode = 1) THEN
                            EditUserBaseRecord (Keuze)
                         ELSE
                             EditAreaBaseRecord (Keuze);
                    END;

           END; { case }
     UNTIL Quit;

     ListErase;
END;


{--------------------------------------------------------------------------}
{ ReadFastEchoNodes                                                        }
{                                                                          }
PROCEDURE ReadFastEchoNodes; FAR;
BEGIN
     ReadFastEchoConfig (1,'nodes');
END;


{--------------------------------------------------------------------------}
{ ReadFastEchoAreas                                                        }
{                                                                          }
PROCEDURE ReadFastEchoAreas; FAR;
BEGIN
     ReadFastEchoConfig (2,'areas');
END;


{--------------------------------------------------------------------------}
{ ReadGEchoAreaFile                                                        }
{                                                                          }
{ Deze routine leest de opgegeven file in. Deze routine zit in een losse   }
{ procedure zodat er met een Exit uitgesprongen kan worden bij fouten.     }
{                                                                          }
PROCEDURE ReadGEchoAreaFile; FAR;

CONST REMOVED = $0010;

TYPE Arr51 = ARRAY[1..51] OF CHAR;
     Arr61 = ARRAY[1..61] OF CHAR;

     AreaFile_Hdr = RECORD
                          HdrSize,
                          RecSize,
                          (* OLD
                          {1.02}
                          Systems : WORD;
                          *)
                          {1.10}
                          MaxConnections : WORD;
                    END;

     AreaFile_GE = RECORD
                         Name         : Arr51;  { AREA tag, must be uppercase, no spaces }
                         Comment      : Arr61;  { Description of the topics discussed in area }
                         path         : Arr51;  { Location where *.MSG files are stored }
                         OriginLine   : Arr61;  { Custom origin line, used if origlinenr = 0 }
                         areanumber   : WORD;   { Area number 1-MAXAREAS, 1-200 = Hudson }
                         Group        : BYTE;   { Group (A-Z) }
                         options      : WORD;   { See --- Area options bits }
                         OriginLineNr : BYTE;   { Origin line (1-20, 0 = custom) }
                         Pkt_Origin   : BYTE;   { Address for the packet/Origin line (0-10) }
                         seenbys      : LONGINT; { Addresses (bits 0-31) to add to the SEEN-BY }
                         maxmsgs      : WORD;    { Maximum number of messages       (MBUTIL Purge) }
                         maxdays      : WORD;    { Maximum age of non-Rcvd messages (MBUTIL Purge) }
                         maxrcvddays  : WORD;    { Maximum age of Rcvd messages     (MBUTIL Purge) }
                         areatype     : BYTE;    { See --- Area type }
                         areaformat   : BYTE;    { See --- Area format }
                         extraoptions : BYTE;    { See --- Extra area option bits }
                    END;

     Address = RECORD
                     Zone,
                     Net,
                     Node,
                     Point : WORD;
               END;

     ConnectionEntry = RECORD
                             Address : Address;
                             Status  : BYTE;
                       END;

VAR AreaFile      : FILE;
    AreaHdr       : AreaFile_Hdr;
    AreaRecord    : AreaFile_GE;
    BytesRead     : WordLong;
    Records       : WORD;
    Lp,Lp2        : WORD;
    AreaRecSize   : WORD;
    Converted     : STRING;
    Connection    : ConnectionEntry;
    SearchAddress : FidoAddrType;
    UserBaseRecNr : UserBaseRecordNrType;
    AreaBaseRecNr : AreaBaseRecordNrType;
    IORes         : BYTE;
    CursorLine    : WORD;
    Abort         : BYTE;
    Grp           : BYTE;

BEGIN
     Assign (AreaFile,Path);
     {$I-} Reset (AreaFile,1); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open '+Path+' (error '+Byte2String (IORes)+')');
          Exit;
     END;

     {$I-} BlockRead (AreaFile,AreaHdr,SizeOf (AreaFile_Hdr),BytesRead); {$I+} IORes:=IOResult;
     IF (IORes <> 0) OR (BytesRead < SizeOf (AreaFile_Hdr)) THEN
     BEGIN
          Error ('Error reading AreaFile header');
          Exit;
     END;

     IF (AreaHdr.RecSize > SizeOf (AreaFile_GE)) THEN
     BEGIN
          Error ('Incompatible AreaFile record size');
          Exit;
     END;

     ListDefine (2,3,Video.Cols-5,Video.Rows-4,Default,'Import '+Path+' results',0);
     CursorLine:=0;

     ReadAreaBaseIndexTable;
     ReadUserBaseIndexTable;

     AreaRecSize:=AreaHdr.MaxConnections*SizeOf (ConnectionEntry)+AreaHdr.RecSize;
     Records:=(FileSize (AreaFile)-AreaHdr.HdrSize) DIV AreaRecSize;

     Abort:=0;

     FOR Lp:=1 TO Records DO
     BEGIN
          Seek (AreaFile,AreaHdr.HdrSize+Longint (AreaRecSize)*Longint (Lp-1));
          {$I-} BlockRead (AreaFile,AreaRecord,AreaHdr.RecSize,BytesRead); {$I+} IORes:=IOResult;

          IF (IORes <> 0) OR (BytesRead <> AreaHdr.RecSize) THEN
          BEGIN
               ListAddItem ('Read error, code '+Byte2String (IORes),65000,Bottom);
               Abort:=1;
               Break; { for }
          END;

          IF ((AreaRecord.Options AND REMOVED) = 0) THEN
          BEGIN
               EmptyAreaDataRecord (AreaData);

               WITH AreaData DO
               BEGIN
                    AreaName_F:=UpCaseString (StrPas (@AreaRecord.Name));
                    AreaName_U:=AreaName_F;
                    Comment:=StrPas (@AreaRecord.Comment);

                    IF (AreaRecord.AreaFormat = 2) THEN
                    BEGIN
                         FidoMsgPath:=StrPas (@AreaRecord.Path);
                         FidoMsgStyle:=FidoMsgType;
                    END;

                    IF (AreaRecord.AreaFormat = 3) THEN
                    BEGIN
                         FidoMsgPath:=StrPas (@AreaRecord.Path);
                         FidoMsgStyle:=JAMType;
                    END;

                    ResetGroupFlags (IsInGroups);

                    { in old set-ups this Group was A-Z; now it is 1-n }
                    Grp:=AreaRecord.Group;
                    IF (Grp IN [Ord ('A'),Ord ('Z')]) THEN
                       Grp:=Grp-Ord ('A')+1;

                    IF (Grp = 0) THEN
                       Grp:=1;

                    IF (Grp > MaxGroups) THEN
                       Grp:=MaxGroups;

                    AddGroupToGroupList (IsInGroups,Grp);
                    FOR Lp2:=1 TO 32 DO
                        IF ((AreaRecord.SeenBys AND (Longint (1) SHL (Lp2-1))) > 0) THEN
                           SetSeenByBit (AreaData.AddSeenByAkas,Lp2);

                    Origin:=AreaRecord.OriginLine;

                    OriginNr:=AreaRecord.OriginLineNr;
                    IF (OriginNr > 2) THEN
                       OriginNr:=1;

                    OriginAka:=AreaRecord.Pkt_Origin+1;
                    IF (OriginAka > MaxAkas) THEN
                    BEGIN
                         OriginAka:=1; { main aka }
                         ListAddItem ('    Invalid OriginAka, changed to 1 (main aka)',65000,Bottom);
                    END;
               END; { with }

               AreaBaseRecNr:=GetAreaBaseRecordNrByAreaName_F (AreaData.AreaName_F);
               IF (AreaBaseRecNr <> NILRecordNr) THEN
               BEGIN
                    ListAddItem ('Area '+AreaData.AreaName_F+' already exists',CursorLine,Bottom);
               END ELSE
               BEGIN
                    Inc (CursorLine);
                    ListAddItem ('Area '+AreaData.AreaName_F+
                                 ' created in group '+BuildSingleGroupDesc (Grp),
                                 CursorLine,Bottom);
                    AreaBaseRecNr:=WriteNewAreaBaseRecord (AreaData);
               END;

               FOR Lp2:=1 TO AreaHdr.MaxConnections DO
               BEGIN
                    {$I-} BlockRead (AreaFile,Connection,SizeOf (ConnectionEntry),BytesRead); {$I+} IORes:=IOResult;
                    IF (IORes <> 0) THEN
                    BEGIN
                         ListAddItem ('Read error, code '+Byte2String (IORes),65000,Bottom);
                         Abort:=1;
                         Break;
                    END;

                    WITH Connection.Address DO
                         IF ((Zone OR Net OR Node OR Point) <> 0) THEN
                         BEGIN
                              SearchAddress.Zone:=Zone;
                              SearchAddress.Net:=Net;
                              SearchAddress.Node:=Node;
                              SearchAddress.Point:=Point;
                              SearchAddress.Domain:='';{FIDONET.ORG';}

                              IF FindUserBaseRecordByFidoAddress (SearchAddress,UserBaseRecNr) THEN
                              BEGIN
                                   Inc (CursorLine);
                                   IF ConnectArea (AreaBaseRecNr,UserBaseRecNr) THEN
                                      ListAddItem ('    '+Fido2Str (SearchAddress)+' already subscribed',CursorLine,Bottom)
                                   ELSE
                                       ListAddItem ('    Connected '+Fido2Str (SearchAddress),CursorLine,Bottom);
                              END ELSE
                                  ListAddItem ('    '+Fido2Str (SearchAddress)+' not in User Base!',65000,Bottom);
                         END;
               END; { for }
          END; { not removed }

          IF KeyPressed AND (ReadKey = kEsc) THEN
             Abort:=2;

          IF (Abort > 0) THEN
             Break; { outer for }

          IF (ListItemCount > 0) THEN
          BEGIN
               ListShow (Double,TRUE);
               ListSetCursorOnItem (CursorLine);
               ListUpdateWindow (TRUE,0,CursorLine);
          END;

     END; { for }

     Close (AreaFile);
     JunkAreaBaseIndexTable;
     JunkUserBaseIndexTable;

     ListAddItem ('',0,Bottom);
     Inc (CursorLine);
     ListAddItem ('Import done. Scroll the list to see the results; Escape/Enter when done ',CursorLine,Bottom);
     ListSetCursorOnItem (CursorLine);
     ListSelect (NoTag,[]);
     ListErase;
END;


{--------------------------------------------------------------------------}
{ ReadGEchoNodeFile                                                        }
{                                                                          }
{ Deze routine kan de Node File van GEcho inlezen en de nodes importeren   }
{ in onze User Base. Deze routine zit in een aparte procudure zodat bij    }
{ fouten meteen met een Exit terug kan worden gesprongen en niet eerst nog }
{ een aantal menus of windows verwijderd hoeft te worden.                  }
{                                                                          }
PROCEDURE ReadGEchoNodeFile; FAR;

TYPE Arr9  = ARRAY[1..9] OF CHAR;
     Arr17 = ARRAY[1..17] OF CHAR;
     Arr36 = ARRAY[1..36] OF CHAR;

     Address = RECORD
                     Zone,Net,Node,Point : WORD;
               END;

     NodeFile_Hdr = RECORD
                          HdrSize : WORD;          { sizeof (NodeFile_Hdr) }
                          RecSize : WORD;          { sizeof (NodeFile_GE)  }
                    END;

     NodeFile_GE = RECORD
                         Address       : Address;   { Address of the system }
                         Sysop         : Arr36;     { Name of the sysop or point }
                         PktPwd        : Arr9;      { Packet (session) password }
                         MgrPwd        : Arr17;     { AreaMgr password }
                         oldGroups     : LONGINT;   { AreaMgr groups (bits 0-25) }
                         Options       : WORD;      { See --- Node option bits }
                         ComprType     : BYTE;      { Compression type (0 - 9, 10 = PKT) }
                         status        : word;      { File attach status. See above }
                         RouteTo       : Address;   { Address to route mail files to }
                         ReadGroup     : LONGINT;   { -- fix -- Moet nog uitzoeken waarvoor }
                         mgrstatus     : WORD;      { AreaMgr message status }
                         compress_ext  : BYTE;      { 0 = 0-9, 1 = 0-F, 2 = 0-Z }
                         maxdays       : WORD;      { Maximum age of mail archive, 0 = Unlimited }

                         { nieuw in 1.20, voornamelijk uplink stuff }
                         groups        : ARRAY[1..32] OF BYTE; { Read/write groups (bits 0-255) }
                         readgroups    : ARRAY[1..32] OF BYTE; { Read groups (bits 0-255) }
                         areafix       : Arr9;      { AreaFix program }
                         outmgrpwd     : Arr17;     { AreaFix password (outbound) }
                         uplinkoptions : BYTE;      { See --- Uplink option bits }
                         unknownareas  : BYTE;      { See --- Unknown areas }
                         default_group : BYTE;      { Default group for added areas }
                   END;

VAR NodeFile   : FILE;
    NodeHdr    : NodeFile_Hdr;
    NodeRecord : NodeFile_GE;
    Tmp        : AreaBaseRecordNrType;
    Lp,
    Records,
    BytesRead  : WordLong;
    IORes      : BYTE;
    CursorLine : WORD;

BEGIN
     Assign (NodeFile,Path);
     ReadUserBaseIndexTable;

     {$I-} Reset (NodeFile,1); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open '+Path+' (error '+Byte2String (IORes)+')');
          Exit;
     END;

     {$I-} BlockRead (NodeFile,NodeHdr,SizeOf (NodeFile_Hdr),BytesRead); {$I+} IORes:=IOResult;
     IF (IORes <> 0) OR (BytesRead < SizeOf (NodeFile_Hdr)) THEN
     BEGIN
          Error ('Error reading NodeFile header');
          Close (NodeFile);
          Exit;
     END;

     IF (NodeHdr.RecSize > SizeOf (NodeFile_GE)) THEN
     BEGIN
          Error ('Incompatible NodeFile record size');
          Close (NodeFile);
          Exit;
     END;

     ListDefine (2,3,Video.Cols-5,Video.Rows-4,Default,'Import '+Path+' results',0);
     CursorLine:=0;

     Records:=(FileSize (NodeFile)-NodeHdr.HdrSize) DIV NodeHdr.RecSize;
     Seek (NodeFile,NodeHdr.HdrSize);       { is maar 1 keer nodig hier... }

     FOR Lp:=1 TO Records DO
     BEGIN
          {$I-} BlockRead (NodeFile,NodeRecord,NodeHdr.RecSize,BytesRead); {$I+} IORes:=IOResult;

          IF (IORes = 0) AND (BytesRead = NodeHdr.RecSize) THEN
          BEGIN
               EmptyUserDataRecord;

               WITH UserData DO
               BEGIN
                    { global }
                    System:=_F;
                    ResetGroupFlags (Groups);
                    FOR Lp:=1 TO 26 DO
                        IF ((NodeRecord.OldGroups AND (Longint (1) SHL (Lp-1))) > 0) THEN
                           AddGroupToGroupList (Groups,Lp);

                    { Fido }
                    Address.Zone:=NodeRecord.Address.Zone;
                    Address.Net:=NodeRecord.Address.Net;
                    Address.Node:=NodeRecord.Address.Node;
                    Address.Point:=NodeRecord.Address.Point;
                    Address.Domain:='' {FIDONET.ORG'};

                    Inc (CursorLine);

                    { Controle of user al bestaat ! }
                    IF FindUserBaseRecordByFidoAddress (UserData.Address,Tmp) THEN
                       ListAddItem ('User '+Fido2Str (UserData.Address)+' already exists',CursorLine,Bottom)
                    ELSE BEGIN
                         ListAddItem ('Adding user '+Fido2Str (UserData.Address),CursorLine,Bottom);

                         Sysop:=StrPas (@NodeRecord.Sysop);
                         AreaFixPwd:=StrPas (@NodeRecord.MgrPwd);
                         PacketPwd:=StrPas (@NodeRecord.PktPwd);

                         CASE NodeRecord.ComprType OF
                              0 : Compression:=fctARC;
                              1 : Compression:=fctARJ;
                              2 : Compression:=fctLZH;
                              3 : Compression:=fctPAK;
                              4 : Compression:=fctZIP;
                              5 : Compression:=fctZOO;
                              6 : BEGIN
                                       ListAddItem ('    SQZ compression not supported; changed to ZIP',65000,Bottom);
                                       Compression:=fctZIP;        { SQZ }
                                  END;
                              7 : BEGIN
                                       ListAddItem ('    UC2 compression not supported; changed to ZIP',65000,Bottom);
                                       Compression:=fctZIP;        { UC2 }
                                  END;
                              8 : Compression:=fctRAR;
                              10: Compression:=fctNone;
                         END; { case }

                         WriteUserBaseRecord (UserBaseRecCount+1,UserData);
                    END; { if not exist }

               END; { with }

          END; { if record is lang genoeg }

          IF (ListItemCount > 0) THEN
          BEGIN
               ListShow (Double,TRUE);
               ListSetCursorOnItem (CursorLine);
               ListUpdateWindow (TRUE,0,CursorLine);
          END;

     END; { for }

     JunkUserBaseIndexTable;
     Close (NodeFile);

     ListAddItem ('',0,Bottom);
     Inc (CursorLine);
     ListAddItem ('Import done. Scroll the list to see the results; Escape/Enter when done ',CursorLine,Bottom);
     ListSetCursorOnItem (CursorLine);
     ListSelect (NoTag,[]);
     ListErase;
END;


{--------------------------------------------------------------------------}
{ ReadWaffleSystemsFile                                                    }
{                                                                          }
{ Deze routine leest uit de SYSTEMS file van waffle alle systeem namen en  }
{ maakt deze in de UserBase aan.                                           }
{                                                                          }
PROCEDURE ReadWaffleSystemsFile; FAR;

VAR SystemsFile : TEXT;
    Regel       : STRING;

BEGIN
     Assign (SystemsFile,Path);
     Reset (SystemsFile);
     PeekFiles;

     WHILE (NOT Eof (SystemsFile)) DO
     BEGIN
          ReadLn (SystemsFile,Regel);

          EmptyUserDataRecord;

          WITH UserData DO
          BEGIN
               System:=_U;
               UUCPName:=Copy (Regel,1,Pos (' ',Regel)-1);
               {MaxDATLength:=0; -> config }
               Compress:=uctCompress;
               CunBatch:=FALSE;
          END; { with }

          WriteUserBaseRecord (UserBaseRecCount+1,UserData);
     END; { while }

     Close (SystemsFile);
     PeekFiles;
END;


{--------------------------------------------------------------------------}
{ ReadUUCicoFeedsFile                                                      }
{                                                                          }
{ Deze routine leest uit de FEEDS file van UUCico alle newsgroups die aan- }
{ gesloten zijn per node.                                                  }
{                                                                          }
PROCEDURE ReadUUCicoFeedsFile; FAR;

TYPE ANameRecordPtr = ^ANameRecord;
     ANameRecord    = RECORD
                            Name  : STRING[MaxLenAreaName];
                            RecNr : AreaBaseRecordNrType;
                            Next  : ANameRecordPtr;
                      END;

VAR FeedsFile : TEXT;
    Regel     : STRING;

    SystemName   : STRING[MaxLenUUCPName];
    HulpUUCPName : STRING[MaxLenUUCPName];
    AreaName     : STRING[MaxLenAreaName];
    ULp          : UserBaseRecordNrType;
    ALp          : AreaBaseRecordNrType;
    P            : BYTE;

    HulpAName,
    FirstAName : ANameRecordPtr;

    Found,
    Connect,
    Astrix,
    Dot        : BOOLEAN;

    PROCEDURE ImportFeedsConnect (AreaBaseRecordNr : AreaBaseRecordNrType);
    BEGIN
         IF Connect THEN AddAreaToUserSubscrToList (UserData,AreaBaseRecordNr)
                    ELSE RemoveAreaFromUserSubscrToList (UserData,AreaBaseRecordNr);

         ReadAreaBaseRecord (AreaBaseRecordNr,AreaData);
         IF Connect THEN AddUserToAreaSubscrList (AreaData,UserDataRecNr)
                    ELSE RemoveUserFromAreaSubscrList (AreaData,UserDataRecNr);
         WriteAreaBaseRecord (AreaBaseRecordNr,AreaData);
    END;

BEGIN
     FirstAName:=NIL;
     Message ('Reading area names');
     FOR ALp:=1 TO AreaBaseRecCount DO
     BEGIN
          ReadAreaBaseRecord (ALp,AreaData);
          IF (NOT AreaData.Deleted) THEN
          BEGIN
               GetMem (HulpAName,SizeOf (ANameRecord));

               WITH HulpAName^ DO
               BEGIN
                    Name:=UpCaseString (DeleteBackSpaces (AreaData.AreaName_F));
                    RecNr:=ALp;
                    Next:=FirstAName;
               END; { with }

               FirstAName:=HulpAName;
          END;
     END;
     WindowPop;

     WindowPush (1,24,80,24);
     SetColor (cBoxData);

     Assign (FeedsFile,Path);
     Reset (FeedsFile);
     PeekFiles;

     SystemName:='';

     WHILE (NOT Eof (FeedsFile)) DO
     BEGIN
          ReadLn (FeedsFile,Regel);

          { Zie '#' & '%' nu correct als feeds }
          IF Regel[1] IN ['#','%'] THEN
             Continue;

          IF (Regel[1] <> ' ') THEN { nieuwe systeem naam }
          BEGIN
               P:=1;
               WHILE NOT (Regel[P] IN [' ','/']) DO
                     Inc (P);

               SystemName:=UpCaseString (Copy (Regel,1,P-1));
               IF (P > 1) THEN Delete (Regel,1,P-1);

               IF (SystemName <> '') THEN
               BEGIN
                    FOR ULp:=1 TO UserBaseRecCount DO
                    BEGIN
                         ReadUserBaseRecord (ULp,UserData);

                         IF (NOT UserData.Deleted) THEN
                         BEGIN
                              HulpUUCPName:=UpCaseString (DeleteBackSpaces (UserData.UUCPName));

                              IF (UserData.System = _U) AND
                                 (HulpUUCPName = SystemName) THEN
                              BEGIN
                                   UserDataRecNr:=ULp;
                                   WriteXY (1,24,AddUpWithSpaces (MaxLenUUCPName,SystemName));
                                   Break;
                              END;
                         END; { not deleted }
                    END; { for }

                    IF (HulpUUCPName <> SystemName) THEN
                    BEGIN
                         Error ('Cannot find UUCPName in UserBase: '+SystemName);
                         SetColor (cBoxData);
                         SystemName:=''; { anders wordt alles op de vorige aangesloten }
                    END;
               END;
          END; { new system name }

          IF (SystemName <> '') THEN
          BEGIN
               Regel:=UpCaseString (Regel);
               Regel:=DeleteFrontSpaces (Regel);

               IF (Regel <> '') AND
                  (Copy (Regel,1,6) = '/BATCH') THEN
               BEGIN
                    Delete (Regel,1,6);

                    Regel:=DeleteFrontSpaces (Regel);

                    IF (Regel[1] = '=') THEN
                       Delete (Regel,1,1);

                    Regel:=DeleteFrontSpaces (Regel);

                    UserData.Compress:=uctNone;
               END;

               IF (Copy (Regel,1,8) = 'COMPRESS') THEN
               BEGIN
                    Delete (Regel,1,8);
                    UserData.Compress:=uctCompress;
                    WriteUserbaseRecord (UserDataRecNr,UserData);
               END;

               { als ie compess gebruikt, dan nu altijd naar 16 bits }
               IF (Copy (Regel,1,6) = 'COMP16') OR
                  (Copy (Regel,1,6) = 'COMP15') OR
                  (Copy (Regel,1,6) = 'COMP14') OR
                  (Copy (Regel,1,6) = 'COMP13') OR
                  (Copy (Regel,1,6) = 'COMP12') THEN
               BEGIN
                    Delete (Regel,1,6);
                    UserData.Compress:=uctCompress;
                    WriteUserbaseRecord (UserDataRecNr,UserData);
               END;

               IF (Copy (Regel,1,3) = 'RAW') THEN
               BEGIN
                    Delete (Regel,1,3);
                    UserData.Compress:=uctCompress;
                    WriteUserbaseRecord (UserDataRecNr,UserData);
               END;

               { Vervang alle spaties door koma's, en verwijder }
               { vervolgens alle dubbele entry's.               }

               Regel:=DeleteFrontAndBackSpaces (Regel);

               WHILE (Pos (' ',Regel) > 0) DO
                     Regel[Pos (' ',Regel)]:=',';

               WHILE (Pos (',,',Regel) > 0) DO
                     Delete (Regel,Pos (',,',Regel),1);

               WHILE (Regel <> '') DO
               BEGIN
                    IF (Pos (',',Regel) = 0) THEN
                    BEGIN
                         AreaName:=Regel;
                         Regel:='';
                    END ELSE
                    BEGIN
                         AreaName:=Copy (Regel,1,Pos (',',Regel)-1);
                         Delete (Regel,1,Pos (',',Regel));
                    END;

                    WriteXY (2+MaxLenUUCPName,24,AddUpWithSpaces (MaxLenAreaName,AreaName));

                    IF (AreaName[1] = '!') THEN
                    BEGIN
                         Connect:=FALSE;
                         Delete (AreaName,1,1);
                    END ELSE
                        Connect:=TRUE;

                    IF (AreaName[Length (AreaName)] = '*') THEN
                    BEGIN
                         Astrix:=TRUE;
                         Delete (AreaName,Length (AreaName),1);
                    END ELSE
                        Astrix:=FALSE;

                    IF (AreaName[Length (AreaName)] = '.') THEN
                    BEGIN
                         Dot:=TRUE;
                         Delete (AreaName,Length (AreaName),1);
                    END ELSE
                        Dot:=FALSE;

                    Found:=FALSE;
                    HulpAName:=FirstAName;
                    WHILE (HulpAName <> NIL) DO
                    BEGIN
                         IF (Copy (HulpAName^.Name,1,Length (AreaName)) = AreaName) THEN
                         BEGIN
                              IF (Length (AreaName) = Length (HulpAName^.Name)) THEN
                              BEGIN
                                   { alleen deze newsgroup }
                                   IF ((NOT Astrix) AND Dot) THEN
                                   BEGIN
                                        Found:=TRUE;
                                        ImportFeedsConnect (HulpAName^.RecNr);
                                   END;

                                   { deze + underlying newsgroups }
                                   IF (NOT (Astrix OR Dot)) THEN
                                   BEGIN
                                        Found:=TRUE;
                                        ImportFeedsConnect (HulpAName^.RecNr);
                                   END;
                              END ELSE
                                  IF ((NOT Dot) OR Astrix) THEN
                                  BEGIN { underlying newsgroups }
                                       Found:=TRUE;
                                       ImportFeedsConnect (HulpAName^.RecNr);
                                  END;
                         END; { part name found }

                         HulpAName:=HulpAName^.Next;
                    END; { while }

                    IF (NOT Found) THEN
                    BEGIN
                         IF (NOT Connect) THEN AreaName:='!'+AreaName;
                         IF Dot THEN AreaName:=AreaName+'.';
                         IF Astrix THEN AreaName:=AreaName+'*';

                         Error ('Cannot match '+AreaName+' for '+SystemName);
                         SetColor (cBoxData);
                    END ELSE
                        WriteUserBaseRecord (UserDataRecNr,UserData);

               END; { while }
          END; { systemname <> '' }
     END; { while }

     Close (FeedsFile);
     PeekFiles;

     WHILE (FirstAName <> NIL) DO
     BEGIN
          HulpAName:=FirstAName;
          FirstAName:=FirstAName^.Next;
          FreeMem (HulpAName,SizeOf (ANameRecord));
     END;

     WindowPop;
END;


{--------------------------------------------------------------------------}
{ ReadUsenetNewsgroupsFile                                                 }
{                                                                          }
{ Deze routine kan newsgroups inlezen en maakt ze automatisch lid van      }
{ de eerste group die in de DefaultUseNetGroups voorkomt.                  }
{                                                                          }
{ De regels in de file moeten het volgende formaat hebben:                 }
{ <newsgroup name> [/MOD <moderator e-mail address>]                       }
{ <newsgroup name> [/MEXP=<number of days to keep>]                        }
{ Als een regel leeg is of begint met DEFAULT dan wordt deze overgeslagen. }
{ Regels waar /MOD achter staat krijgen de Moderated vlag gezet.           }
{                                                                          }
PROCEDURE ReadUsenetNewsGroupsFile; FAR;

VAR NewsFile       : TEXT;
    Regel          : STRING[100];
    AreaName       : STRING[MaxLenAreaName];
    AreaBaseRecNr  : AreaBaseRecordNrType;

    PROCEDURE ProcessCommands;

    VAR Error : ValNop;

    BEGIN
         WHILE (Regel <> '') DO
         BEGIN
              Regel:=Regel+' ';
              Regel:=DeleteFrontSpaces (Regel);

              IF (Copy (Regel,1,4) = '/MOD') THEN
              BEGIN
                   AreaData.Moderated:=mdUSE;
                   IF (Regel[5] = '=') THEN
                      AreaData.Moderator:=DeleteBackSpaces (Copy (Regel,6,Pos (' ',Regel)));
              END;

              IF (Copy (Regel,1,6) = '/MEXP=') THEN
              BEGIN
                   Val (Copy (Regel,7,Pos (' ',Regel)-7),AreaData.FidoMsgLimit,Error);
                   IF (Error > 0) THEN
                      AreaData.FidoMsgLimit:=Config.DefNumbToKeep_F;
              END;

              { Naar het volgende commando }
              Delete (Regel,1,Pos (' ',Regel));
         END; {While}
    END;

{ReadUsenetNewsgroupsFile}

VAR Groups         : GroupFlagType;
    IndexValue     : IndexValueType;
    CreateCount,
    UpdateCount    : LONGINT;
    IORes          : BYTE;

BEGIN
     Groups:=Config.DefGroups_U;
     REPEAT
          EditGroupsList (Groups,'Add areas to these groups','<connect to NO groups>',0,0);

          IF TestGroupListIsEmpty (Groups) THEN
             Error ('Areas must be in at least 1 group!');

     UNTIL (NOT TestGroupListIsEmpty (Groups));

     ReadAreaBaseIndexTable;

     WindowPush (1,24,80,24);
     SetColor (cBoxBack);

     Assign (NewsFile,Path);
     {$I-} Reset (NewsFile); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Unable to open '+DeleteBackspaces (Path));
          Exit;
     END;

     CreateCount:=0;
     UpdateCount:=0;

     WHILE (NOT Eof (NewsFile)) DO
     BEGIN
          ReadLn (NewsFile,Regel);
          Regel:=CleanTabs (Regel,1);  { Vervang Tabs door een spatie }

          IF (Regel <> '') AND (NOT (Regel[1] IN [' ','#'])) AND (UpCaseString (Copy (Regel,1,7)) <> 'DEFAULT') THEN
          BEGIN
               EmptyAreaDataRecord (AreaData);

               Regel:=UpCaseString (Regel);
               IF (Pos (' ',Regel) = 0) THEN
                  Regel:=Regel+' ';

               AreaData.AreaName_F:=Copy (Regel,1,Pos (' ',Regel)-1);
               AreaData.AreaName_U:=AreaData.AreaName_F;
               AreaData.IsInGroups:=Groups;

               WriteXY (1,24,AddUpWithSpaces (MaxLenAreaName,AreaData.AreaName_F));

               Delete (Regel,1,Pos (' ',Regel));
               Regel := DeleteFrontSpaces( Regel );

{               WHILE ((Regel[1] = ' ') AND (Length(Regel)>0)) DO Delete (Regel,1,1); }
               ProcessCommands;

               { RWI 950621: it now uses the Usenet name, because the Fido }
               {             name might have been altered.                 }
               IndexValue:=GetAreaNameIndexValue (AreaData.AreaName_U);
               AreaBaseRecNr:=GetAreaBaseRecordNrByIndexValue_U (IndexValue);
               IF (AreaBaseRecNr = NILRecordNr) THEN
               BEGIN
                    { create a new area }
                    AddIndexValueToAreaBaseIndexTable (GetAreaNameIndexValue (AreaData.AreaName_U));
                    WriteNewAreaBaseRecord (AreaData);
                    Inc (CreateCount);
               END ELSE
               BEGIN
                    ReadAreaBaseRecord (AreaBaseRecNr,AreaData);
                    ProcessCommands;
                    WriteAreaBaseRecord (AreaBaseRecNr,AreaData);
                    Inc (Updatecount);
               END;
          END;

     END; { while not eof }

     Close (NewsFile);

     WindowPop; { regel 24 }
     JunkAreaBaseIndexTable;

     PushKeysLine;
     WriteKeysLine (' Press any key to continue');
     Message ('Created '+Longint2String (CreateCount)+' new areas and updated '+Longint2String (UpdateCount)+' areas.');
     ReadKey;
     WindowPop; { message }
     PopKeysLine;
END;


{--------------------------------------------------------------------------}
{ ReadUsenetPathsFile                                                      }
{                                                                          }
{ Deze routine leest de PATHS file in en breidt de domain adressen van de  }
{ usenet nodes uit met de domain adressen die in de paths file staan.      }
{                                                                          }
PROCEDURE ReadUsenetPathsFile; FAR;

VAR PathsFile   : TEXT;
    Regel       : STRING;
    DomainAdres,
    HulpDomain  : STRING[MaxLenDomain];
    UUCPName    : STRING[MaxLenUUCPName];
    DomainLp    : 1..MaxUserDomains;
    ULp         : UserBaseRecordNrType;

BEGIN
     Assign (PathsFile,Path);
     Reset (PathsFile);
     PeekFiles;

     WHILE (NOT Eof (PathsFile)) DO
     BEGIN
          ReadLn (PathsFile,Regel);

          IF (Regel <> '') THEN
          BEGIN
               DomainAdres:=Copy (Regel,1,Pos (' ',Regel)-1);
               Delete (Regel,1,Pos (' ',Regel));
               WHILE (Regel[1] = ' ') DO Delete (Regel,1,1);
               UUCPName:=UpCaseString (Regel);

               FOR ULp:=1 TO UserBaseRecCount DO
               BEGIN
                    ReadUserBaseRecord (ULp,UserData);

                    IF (UpCaseString (UserData.UUCPName) = UUCPName) THEN
                    BEGIN
                         FOR DomainLp:=1 TO MaxUserDomains DO
                         BEGIN
                              HulpDomain:=UpCaseString (DeleteBackSpaces (UserData.Domains[DomainLp]));

                              IF (HulpDomain = DomainAdres) THEN
                                 Break;

                              IF (HulpDomain = '') THEN
                              BEGIN
                                   UserData.Domains[DomainLp]:=DomainAdres;
                                   WriteUserBaseRecord (ULp,UserData);
                                   Break;
                              END;
                         END; { for }
                    END; { UUCP name found }
               END; { for }
          END; { regel <> '' }
     END; { not eof }

     Close (PathsFile);
     PeekFiles;
END;


(*
{--------------------------------------------------------------------------}
{ ReadAreaFixAlikeFile                                                     }
{                                                                          }
PROCEDURE ReadAreaFixAlikeFile; FAR;

VAR AFixFile  : TEXT;
    Regel     : STRING;
    Lp        : UserBaseRecordNrType;
    IORes     : BYTE;
    Keuze     : SelectItemNrType;
    Connect   : BOOLEAN;
    AreaRecNr : AreaBaseRecordNrType;

BEGIN
     Assign (AFixFile,Path);
     {$I-} Reset (AFixFile); {$I+} IORes:=IOResult;
     PeekFiles;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open file '+Path);
          Exit;
     END;

     SelectDefine (3,3,50,20,'Select a user');
     FOR Lp:=1 TO UserBaseRecCount DO
     BEGIN
          ReadUserBaseRecord (Lp,UserData);

          IF (NOT UserData.Deleted) THEN
             IF (UserData.System = _F) THEN
                SelectAddItemSorted (Fido2Str (UserData.Address)+
                                     ' ('+DeleteBackSpaces (UserData.Sysop)+')',Lp)
             ELSE
                 SelectAddItemSorted (DeleteBackSpaces (UserData.UUCPName)+
                                      ' ('+DeleteBackSpaces (UserData.Organization)+')',Lp);
     END;
     IF (SelectItemCount = 0) THEN
        SelectAddItemAtBottom ('<no configured users>',65535);

     SelectShow;
     Keuze:=SelectSelect (NoTag);
     IF (Key = kRet) THEN
     BEGIN
          Message ('Updating connected areas list');
          WindowPush (1,24,80,24);
          ReadAreaBaseIndexTable;
          ReadUserBaseRecord (Keuze,UserData);

          WHILE (NOT Eof (AFixFile)) DO
          BEGIN
               ReadLn (AFixFile,Regel);
               WriteXYC (1,24,cBoxBack,AddUpWithSpaces (80,Regel));

               IF (Regel[1] = '-') THEN
                  Connect:=FALSE
               ELSE
                   IF (Regel[1] = '+') THEN
                      Connect:=TRUE
                   ELSE
                       Error ('Unknown switch at beginning of line: '+Regel[1]);
               Delete (Regel,1,1);

               AreaRecNr:=GetAreaBaseRecordNrByAreaName (Regel);
               IF (AreaRecNr <> NILRecordNr) THEN
               BEGIN
                    IF Connect THEN AddAreaToUserSubscrToList (UserData,AreaRecNr)
                               ELSE RemoveAreaFromUserSubscrToList (UserData,AreaRecNr);
               AreaRecNr:=GetAreaBaseRecordNrByAreaName (Regel);
               IF (AreaRecNr <> NILRecordNr) THEN
               BEGIN
                    IF Connect THEN AddAreaToUserSubscrToList (UserData,AreaRecNr)
                               ELSE RemoveAreaFromUserSubscrToList (UserData,AreaRecNr);

                    ReadAreaBaseRecord (AreaRecNr,AreaData);
                    IF Connect THEN AddUserToAreaSubscrList (AreaData,Keuze)
                               ELSE RemoveUserFromAreaSubscrList (AreaData,Keuze);
                    WriteAreaBaseRecord (AreaRecNr,AreaData);
               END;
               {ELSE: Area does not exist}
          END;

          WriteUserBaseRecord (Keuze,UserData);
          JunkAreaBaseIndexTable;
          WindowPop; { 24th line }
          WindowPop;
     END;

     SelectErase;
     Close (AFixFile);
     PeekFiles;
END;


{--------------------------------------------------------------------------}
{ ImportAreaFixAlikeFile                                                   }
{                                                                          }
{ Met deze routine kan een file met area namen met daarvoor een + of -     }
{ worden ingelezen. De user waarvoor de file gaat gelden moet worden uit-  }
{ gekozen.                                                                 }
{                                                                          }
PROCEDURE ImportAreaFixAlikeFile;
BEGIN
     EnterAndImport (TRUE,'GECHO\AREAS.LST',ReadAreaFixAlikeFile);
END;
*)


{--------------------------------------------------------------------------}
{ ReadSquishConfig                                                         }
{                                                                          }
{ Importeert een Squish configuratie bestand, loop door een configuratie   }
{ bestand en pik de regels die beginnen met 'EchoArea' eruit.              }
{                                                                          }
PROCEDURE ReadSquishConfig; FAR;

VAR LineNumber    : WORD;
    CursorLine    : WORD;
    ImportInGroup : GroupFlagType;
    AreaRec       : AreaBaseRecord;
    AreaRecNr     : AreaBaseRecordNrType;
    OrigRegel     : STRING;

    {----------------------------------------------------------------------}
    { GetNumber                                                            }
    {                                                                      }
    PROCEDURE GetNumber (VAR Invoer : STRING; VAR Uitvoer : INTEGER);

     VAR P   : BYTE;
         Nop : ValNop;

    BEGIN
         P:=1; { Eerst teken is hier niet interessant }
         WHILE (P <= Length (Invoer)) AND (Invoer[P+1] IN ['0'..'9']) DO
               Inc (P);

         IF (P > 1) THEN
            Val (Copy (Invoer,2,P-1),Uitvoer,Nop);

         Invoer:=Copy (Invoer,P+1,255);
    END;

    {----------------------------------------------------------------------}
    { CreateArea                                                           }
    {                                                                      }
    { This routine processes the first part of a line. It checks whether   }
    { all items are present and then creates the area, unless it already   }
    { exists. It returns the area record number and the updated Regel with }
    { the area related items removed.                                      }
    {                                                                      }
    PROCEDURE CreateArea (VAR Regel : STRING);

    VAR Path,
        AreaName  : STRING;

    BEGIN
         AreaRecNr:=NILRecordNr; { indicates error }

         GetItem (Regel,AreaName);
         GetItem (Regel,Path);

         IF (AreaName = '') OR (Path = '') THEN
         BEGIN
              ListAddItem ('Error in line '+Word2String (LineNumber)+': '+OrigRegel,65000,Bottom);
              Exit;      { ## EXIT ## }
         END;

         IF (Length (AreaName) > MaxLenAreaName) THEN
         BEGIN
              ListAddItem ('Area name too long: "'+AreaName+'"',65000,Bottom);

              AreaName:=Copy (AreaName,1,MaxLenAreaName);

              Inc (CursorLine);
              ListAddItem ('     Changing into: "'+AreaName+'"',CursorLine,Bottom);
         END;

         IF (Length (Path) > MaxLenPath) THEN
         BEGIN
              ListAddItem ('Path is too long: "'+Path+'"',65000,Bottom);

              Path:=Copy (Path,1,MaxLenPath);

              Inc (CursorLine);
              ListAddItem ('     Changing into: "'+Path+'"',CursorLine,Bottom);
         END;

         AreaRecNr:=GetAreaBaseRecordNrByAreaName_F (AreaName);
         IF (AreaRecNr = NILRecordNr) THEN
            AreaRecNr:=GetAreaBaseRecordNrByAreaName_U (AreaName);

         IF (AreaRecNr <> NILRecordNr) THEN
         BEGIN
              Inc (CursorLine);
              ListAddItem ('Area "'+AreaName+'" already exists',CursorLine,Bottom);

              ReadAreaBaseRecord (AreaRecNr,AreaRec);
              Exit;       { ## EXIT ## }
         END;

         { create a new record }
         EmptyAreaDataRecord (AreaRec);

         AreaRec.AreaName_F:=UpCaseString (AreaName);
         AreaRec.AreaName_U:=LoCaseString (AreaName);

         AreaRec.IsInGroups:=ImportInGroup;

         AreaRec.FidoMsgStyle:=FidoMsgType; { Default; overwritten later on }
         AreaRec.FidoMsgPath:=Path;

         Inc (CursorLine);
         ListAddItem ('Created area '+AreaRec.Areaname_F,CursorLine,Bottom);

         AreaRecNr:=WriteNewAreaBaseRecord (AreaRec);
    END;

    {----------------------------------------------------------------------}
    { ProcessRest                                                          }
    {                                                                      }
    { This routine processes the rest of a squish.cfg line, when the area  }
    { related parts have been removed already. AreaRec contains the latest }
    { area record data and AreaRecNr holds its record number.              }
    {                                                                      }
    PROCEDURE ProcessRest (Regel : STRING);

    VAR NewAKA,
        LastAdres : FidoAddrType;
        Item      : STRING;
        Dummy     : INTEGER;
        Nop       : ValNop;
        Value     : WORD;
        UserRecNr : UserBaseRecordNrType;

    BEGIN
         LastAdres:=Config.NodeNrs[1];

         { vanaf hier is het prijs schieten }
         WHILE (Regel <> '') DO
         BEGIN
              GetItem (Regel,Item);
              Item:=UpCaseString (Item);

              { -$  Squish style area }
              IF (Copy (Item,1,2) = '-$') THEN
              BEGIN
                   AreaRec.FidoMsgStyle:=SquishType;

                   Delete (Item,1,2);
                   Item:=Item+' ';

                   WHILE (Item <> '') DO
                   BEGIN
                        CASE Item[1] OF
                             'G' : {group - ignore}Item:='';
                             'N' : {name - -ignore}Item:='';
                             'M' : GetNumber (Item,AreaRec.FidoMsgLimit);
                             'D' : GetNumber (Item,AreaRec.FidoMsgAge);
                             'S' : GetNumber (Item,Dummy);  {ignore}
                             ' ' : ;
                             ELSE BEGIN
                                  ListAddItem ('Unexpected "'+Item[1]+'" in line '+Word2String (LineNumber)+': '+OrigRegel,
                                               65000,Bottom);
                                  Break;
                             END;
                        END; { case }

                        Item:=DeleteFrontSpaces (Item);
                   END; { while }

                   WriteAreaBaseRecord (AreaRecNr,AreaRec);
                   Continue;
              END; { SquishType }

              { -f  Fido style area (default) }
              IF (Item = '-F') THEN
              BEGIN
                   AreaRec.FidoMsgStyle:=FidoMsgType;
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);
                   Continue;
              END;

              IF (Item = '-J') THEN
              BEGIN
                   AreaRec.FidoMsgStyle:=JAMType;
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);
                   Continue;
              END;

              { -0 PassThru area, berichten worden niet geimporteerd }
              IF (Item = '-0') THEN
              BEGIN
                   AreaRec.FidoMsgStyle:=NoneType;
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);
                   Continue;
              END;

              { -s  Strip private bit (not supported) }
              IF (Item = '-S') THEN
                 Continue;

              { -x  Stops node from sending (not supported) }
              IF (Item = '-X') THEN
                 Continue;

              { Kies een ander primary adres voor deze area }
              IF (Copy (Item,1,2) = '-P') THEN
              BEGIN
                   FidoSplit (Copy (Item,3,255),NewAKA);

                   IF (NOT FidoOurAdres (NewAKA)) THEN
                   BEGIN
                        ListAddItem ('    Unknown origin AKA '+Fido2Str (NewAKA),65000,Bottom);
                        Continue;
                   END;

                   AreaRec.OriginAka:=OurAkaIndex;
                   SetSingleSeenByBit (AreaRec.AddSeenByAkas,OurAkaIndex);
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);

                   Continue;
              END;

              { voeg een AKA toe voor deze area }
              IF (Copy (Item,1,2) = '-+') THEN
              BEGIN
                   FidoSplit (Copy (Item,3,255),NewAKA);

                   IF (NOT FidoOurAdres (NewAKA)) THEN
                   BEGIN
                        ListAddItem ('    Seen-by AKA '+Fido2Str (NewAKA)+' is not a system AKA!',65000,Bottom);
                        Continue;
                   END;

                   SetSeenByBit (AreaRec.AddSeenByAkas,OurAkaIndex);
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);

                   Continue;
              END;

              { Het maximum aantal berichten dat in de area geplaatst mag worden }
              IF (Copy (Item,1,2) = '-M') THEN
              BEGIN
                   Val (Copy (Item,3,255),Value,Nop);

                   IF (Nop <> 0) THEN
                   BEGIN
                        ListAddItem ('    Invalid number (-M) in line '+Word2String (LineNumber)+': '+OrigRegel,65000,Bottom);
                        Continue;
                   END;

                   AreaRec.FidoMsgLimit:=Value;
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);

                   Continue;
              END;

              { Het maximum aantal dagen dat een bericht mag blijven }
              IF (Copy (Item,1,2) = '-D') THEN
              BEGIN
                   Val (Copy (Item,3,255),Value,Nop);

                   IF (Nop <> 0) THEN
                   BEGIN
                        ListAddItem ('    Invalid number (-D) in line '+Word2String (LineNumber)+': '+OrigRegel,65000,Bottom);
                        Continue;
                   END;

                   AreaRec.FidoMsgAge:=Value;
                   WriteAreaBaseRecord (AreaRecNr,AreaRec);

                   Continue;
              END;

              { Alles anders is adres informatie ... }
              FidoSplit (Item,NewAKA);
              FidoMergeAdres (LastAdres,NewAKA);
              LastAdres:=NewAKA;

              { Probeer of we deze user een area kunnen aansmeren }
              IF (NOT FindUserBaseRecordByFidoAddress (NewAKA,UserRecNr)) THEN
              BEGIN
                   ListAddItem ('    System '+Fido2Str (NewAKA)+' not in User Base!',65000,Bottom);
                   Continue;
              END;

              { add user to area list, if not already subscribed }
              Inc (CursorLine);
              IF ConnectArea (AreaRecNr,UserRecNr) THEN
                 ListAddItem ('    '+Fido2Str (NewAKA)+' already subscribed',CursorLine,Bottom)
              ELSE BEGIN
                   ListAddItem ('    Connected '+Fido2Str (NewAKA),CursorLine,Bottom);
                   ReadAreaBaseRecord (AreaRecNr,AreaRec);
              END;
         END; { while }
    END;

    {----------------------------------------------------------------------}
    { HandleAddress                                                        }
    {                                                                      }
    PROCEDURE HandleAddress (Regel : STRING);

    VAR Item   : STRING;
        NewAKA : FidoAddrType;
        AkaLp  : 1..MaxAkas;

    BEGIN
         GetItem (Regel,Item);
         FidoSplit (Item,NewAKA);

         IF FidoOurAdres (NewAKA) THEN
            Exit;

         ListAddItem ('Adding '+Fido2Str (NewAKA)+' as system AKA',CursorLine,Bottom);

         FOR AkaLp:=1 TO MaxAkas DO
             IF (FidoCompare (Config.NodeNrs[AkaLp],NullAdres)) THEN
             BEGIN
                  Config.NodeNrs[AkaLp]:=NewAKA;
                  SaveConfigFile;
                  Exit;
             END;

         ListAddItem ('   No place to add new system AKA!',65000,Bottom);
    END;

{ReadSquishConfig}

VAR SquishConfig : TEXT;
    Regel        : STRING;
    Item         : STRING;
    IORes        : BYTE;
    PrintCount   : WORD;

BEGIN
     ImportInGroup:=Config.DefGroups_F;
     WHILE TRUE DO
     BEGIN
          EditGroupsList (ImportInGroup,'Selects group(s) to create areas in','<No groups>',0,0);
          IF TestGroupListIsEmpty (ImportInGroup) THEN
             Error ('You must select at least one group!')
          ELSE
              Break;
     END;

     { Open de configuratie Squish file }
     Assign (SquishConfig,Path);
     {$I-} Reset (SquishConfig); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open file '+Path);
          Exit;
     END;

     ListDefine (2,3,Video.Cols-5,Video.Rows-4,Default,'Import '+Path+' results',0);
     CursorLine:=0;
     PrintCount:=0;

     ReadAreaBaseIndexTable;
     ReadUserBaseIndexTable;

     { doorloop het configuratie bestand regel voor regel }
     LineNumber:=0;
     WHILE (NOT Eof (SquishConfig)) DO
     BEGIN
          IF (ListItemCount <> PrintCount) THEN
          BEGIN
               ListShow (Double,TRUE);
               ListSetCursorOnItem (CursorLine);
               ListUpdateWindow (TRUE,0,CursorLine);
               PrintCount:=ListItemCount;
          END;

          IF KeyPressed AND (ReadKey = kEsc) THEN
          BEGIN
               ListAddItem ('Aborted by operator',65000,Bottom);
               Break;
          END;

          ReadLn (SquishConfig,Regel);
          Inc (LineNumber);

          IF ((LineNumber MOD 25) = 1) THEN
             Slice_Now;

          IF (Regel = '') OR (Regel[1] = ';') THEN
             Continue;

          Regel:=CleanTabs (Regel,1);

          OrigRegel:=Regel;

          { Kijk of we met een EchoArea regel te doen hebben }
          GetItem (Regel,Item);
          Item:=UpCaseString (Item);

          IF (Item = 'ECHOAREA') THEN
          BEGIN
               {ListAddItem ('In: '+OrigRegel,0,Bottom);}

               CreateArea (Regel);

               IF (AreaRecNr <> NILRecordNr) THEN
                  ProcessRest (Regel);

               Continue;
          END;

          IF (Item = 'ADDRESS') THEN
          BEGIN
               { add system AKA }
               HandleAddress (Regel);
               Continue;
          END;

          {ListAddItem ('Unknown keyword in line '+Word2String (LineNumber)+': '+OrigRegel,65000,Bottom);}
     END; { while }

     { de-Initialisatie }
     Close (SquishConfig); { RWI 970205: added }

     JunkUserBaseIndexTable;
     JunkAreaBaseIndexTable;

     Inc (CursorLine);
     ListAddItem ('',0,Bottom);
     ListAddItem ('Import done. Scroll the list to see the results; Escape/Enter when done ',CursorLine,Bottom);
     ListSetCursorOnItem (CursorLine);

     ListSelect (DoTag,[]);
     ListErase;
END;


{--------------------------------------------------------------------------}
{ WriteSquishConfig                                                        }
{                                                                          }
{ Deze routine schrijft een lijstje met alle areas in Squish formaat naar  }
{ disk.                                                                    }
{                                                                          }
{ MD 12-10-93 Aanvulling, JAM areas worden ook meegeschreven, doormiddel   }
{             van een ;                                                    }
{                                                                          }
PROCEDURE WriteSquishConfig; FAR;

VAR SquishConfig  : TEXT;
    LastUserAdres : FidoAddrType;
    Lp            : WORD;
    AantalAreas,
    AreaTeller    : AreaBaseRecordNrType;
    Regel         : STRING;
    Search        : SubscrSearchRecord;

    { CreateSquishLine                                           }
    {                                                            }
    { Algemene functie om een Squish line te bouwen.             }
    { Alles hierheen verplaatst om Netmail & Badmail zonder veel }
    { troubles te implementeren.                                 }

    FUNCTION CreateSquishLine (AreaDesc : STRING;
                               Path     : STRING;
                               BaseType : FidoMsgStyleType;
                               MsgAge   : INTEGER;
                               MsgLimit : INTEGER) : STRING;

    VAR Regel : STRING;

    BEGIN
         Regel:=AreaDesc;

         IF (BaseType IN [SquishType,JAMType,FidoMsgType]) THEN
            Regel:=Regel+' '+AddUpWithSpacesNoCut (30,DeleteBackSpaces (Path))+' ';

         IF BaseType = NoneType THEN
            Regel:=Regel+' '+AddUpWithSpacesNoCut (30,Config.DefaultFidoMsgPath)+' ';

         CASE BaseType OF
              NoneType    : Regel:=Regel+'-0 ';
              FidoMsgType : Regel:=Regel+'-f ';
              SquishType  : Regel:=Regel+'-$ ';
              JamType     : Regel:=Regel+'-J ';
         END;

         { zorg dat de limieten vermeld worden }
         IF (MsgLimit > 0) THEN
         BEGIN
              IF (BaseType = SquishType) THEN
                 Regel:=Regel+'-$m'
              ELSE
                  Regel:=Regel+'-m';

              Regel:=Regel+Word2String (MsgLimit)+' ';
         END;

         IF (MsgAge > 0) THEN
         BEGIN
              IF (BaseType = SquishType) THEN
                 Regel:=Regel+'-$d'
              ELSE
                  Regel:=Regel+'-d';

              Regel:=Regel+Word2String (MsgAge)+' ';
         END;

        CreateSquishLine:=Regel;
   END; { createSquishLine }

{WriteSquishConfig}

VAR IORes : BYTE;

BEGIN
     { open de configuratie Squish file }
     Assign (SquishConfig,Path);
     {$I-} Rewrite (SquishConfig); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          IF Desktop THEN
             Error ('Cannot open file '+Path);
          Exit;
     END;

     IF Desktop THEN
        Message ('Exporting areas, please wait...')
     ELSE
         WriteLn ('Exporting Squish Config ('+Path+')');

     ReadAreaBaseIndexTable;

     {---------------------------------------------------}
     { Squish Header schrijven                           }

     WriteLn (SquishConfig,'; Squish Area Configuration');
     WriteLn (SquishConfig,'; '+FidoCurrTime2Str);
     WriteLn (SquishConfig,';');
     WriteLn (SquishConfig,'; Created by '+DesktopProgramName+' v'+FullProgramVersion);
     WriteLn (SquishConfig,';');

     {------------------------}
     { Addresses              }

     FOR Lp:=1 TO MaxAkas DO
     BEGIN
          Regel:=Fido2Str (Config.NodeNrs[Lp]);
          IF (Regel <> '0') THEN
             WriteLn (SquishConfig,'Address '+Regel);
     END; { for }

     WriteLn (SquishConfig,';');

     {------------------------}
     { Netmail                }

     Regel:=CreateSquishLine ('NetArea NETMAIL    ',
                              Config.FidoNetmailPath,
                              Config.FidoNetmailType,
                              Config.DefNumbToKeep_F,
                              Config.DefDaysToKeep_F);

     WriteLn (SquishConfig,Regel);

     {------------------------}
     { Badmail                }

     IF (Config.FidoBadAreaType <> NoneType) THEN
     BEGIN
          Regel:=CreateSquishLine ('BadArea BAD_MSGS   ',
                                   Config.FidoBadPath,
                                   Config.FidoBadAreaType,
                                   Config.DefNumbToKeep_F,
                                   Config.DefDaysToKeep_F);

          WriteLn (SquishConfig,Regel);
     END;

     {------------------------}
     { Dupe area              }

     IF (Config.FidoDupeAreaType  <> NoneType) THEN
     BEGIN
          Regel:=CreateSquishLine ('DupeArea DUPE_MSGS ',
                                   Config.FidoDupePath,
                                   Config.FidoDupeAreaType,
                                   Config.DefNumbToKeep_F,
                                   Config.DefDaysToKeep_F);

          WriteLn (SquishConfig,Regel);
     END;

     { Scheiding tussen netmail,badmail & echomail }
     WriteLn (SquishConfig,';');

     {------------------------}
     { Echomail               }

     AantalAreas:=AreaBaseRecCount;

     FOR AreaTeller:=1 TO AantalAreas DO
     BEGIN
          ReadAreaBaseRecord (AreaTeller,AreaData);

          IF (NOT AreaData.Deleted) AND (AreaData.AreaName_F <> '') THEN
          BEGIN
               Regel:=CreateSquishLine ('EchoArea '+AddUpWithSpacesNoCut (30,DeleteBackSpaces (AreaData.AreaName_F)),
                                        AreaData.FidoMsgPath,
                                        AreaData.FidoMsgStyle,
                                        AreaData.FidoMsgAge,
                                        AreaData.FidoMsgLimit);

               { Zorg dat het goed aka erbij vermeld is }
               { IF (AreaData.OriginAKA > 1) THEN }

               Regel:=Regel+'-p'+Fido2Str (Config.NodeNrs[AreaData.OriginAka])+' ';

               { Zorg dat de extra aka's ook vermeld zijn }
               FOR Lp:=1 TO MaxAkas DO
                   IF (Lp <> AreaData.OriginAKA) AND HasSeenByBit (AreaData.AddSeenByAkas,Lp) THEN
                      Regel:=Regel+'-+'+Fido23DStr (Config.NodeNrs[Lp])+' ';

               { Doorloop de lijst met aangesloten gebruikers }
               GetFirstUserSubscribedToThisArea (AreaData.UserList,Search);
               FidoSplit ('0',LastUserAdres);

               WHILE Search.Found DO
               BEGIN
                    ReadUserBaseRecord (Search.UserBaseRecordNr,UserData);
                    IF (UserData.System = _F) THEN
                    BEGIN
                         Regel:=Regel+FidoMinimal (LastUserAdres,UserData.Address)+' ';
                         LastUserAdres:=UserData.Address;
                    END;

                    GetNextUserSubscribedToThisArea (Search);
               END;

               WriteLn (SquishConfig,Regel);

          END; { if not deleted }
     END; { for areas loop }

     WriteLn (SquishConfig,';');
     WriteLn (SquishConfig,'; end of file squish.cfg');

     Close (SquishConfig);
     JunkAreaBaseIndexTable;   { BugFix 3/11/93 }
     IF Desktop THEN
        WindowPop;
END;


{--------------------------------------------------------------------------}
{ ExportSquishConfig                                                       }
{                                                                          }
PROCEDURE ExportSquishConfig (Param : STRING);
BEGIN
     IF (Param = '') THEN
     BEGIN
          Desktop:=TRUE;
          EnterAndImport (FALSE,'SQUISH.CFG',WriteSquishConfig,8);
     END ELSE
     BEGIN
          Desktop:=FALSE;
          Path:=Param;
          WriteSquishConfig;
     END;
END;


{--------------------------------------------------------------------------}
{ ReadAreasBBS                                                             }
{                                                                          }
{ Leest een standaard AREAS.BBS file in het geheugen.                      }
{ Formaat:                                                                 }
{                                                                          }
{ Origin!Sysop                                                             }
{ ;                                                                        }
{ P AREANAME 2:280/802 12 14 .12  Passthrough (echo)                       }
{ 134 AREANAME ...                Hudson                                   }
{ PATH AREANAME ...               *.MSG                                    }
{ %PATH AREANAME ...              Squish (niet gewild / fout ??)           }
{ $PATH AREANAME ...              Squish (preferred)                       }
{ !PATH AREANAME ...              JAM                                      }
{                                                                          }
PROCEDURE ReadAREASBBS; FAR;

VAR AreasBBS       : TEXT;
    Item1,
    Item,
    Regel          : STRING;
    ImportInGroup  : GroupFlagType;
    NewAdres,
    LastAdres      : FidoAddrType;
    AreaBaseRecNr  : AreaBaseRecordNrType;
    IndexValue     : LONGINT;
    UserBaseRecNr  : UserBaseRecordNrType;
    UserRec        : UserBaseRecord;
    CursorLine     : WORD;
    IORes          : BYTE;

BEGIN
     Assign (AreasBBS,Path);
     {$I-} Reset (AreasBBS); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open file '+Path+' (error '+Byte2String (IORes)+')');
          Exit;
     END;

     ImportInGroup:=Config.DefGroups_F;
     WHILE TRUE DO
     BEGIN
          EditGroupsList (ImportInGroup,'Add areas to these groups','<connect to NO Groups>',0,0);
          IF TestGroupListIsEmpty (ImportInGroup) THEN
             Error ('Areas must be in at least 1 group!')
          ELSE
              Break;
     END;

     ListDefine (2,3,Video.Cols-5,Video.Rows-4,Default,'Import '+Path+' results',0);
     CursorLine:=0;

     ReadAreaBaseIndexTable;
     ReadUserBaseIndexTable;

     { Skip altijd de eerste regel van een areas.BBS regel }
     { Deze bevat de old-time Origin+Sysop_Name            }
     {$I-} ReadLn (AreasBBS); {$I+} IORes:=IOResult; { schijt als dit mislukt }

     WHILE (NOT Eof (AreasBBS)) DO
     BEGIN
          { lees een regel in }
          {$I-} ReadLn (AreasBBS,Regel); {$I+} IORes:=IOResult;
          IF (IORes <> 0) THEN
             Break; { uit de while }

          Regel:=DeleteBackSpaces (Regel);

          { skip regels die beginnen met een ';' }
          IF (Regel = '') OR (Regel[1] = ';') THEN
             Continue;

          { Skip altijd het eerste item, dit kan een nummer zijn (QBBS)   }
          { of 'P' voor passthrough areas.                                }
          { --- NIET MEER ---  RWI 191094                                 }
          { Een P wordt een echo area zonder message base (passthrough).  }
          { Een nummer wordt een local area zonder message base.          }
          { Een pad wordt een echo area met *.MSG message base.           }
          { Een % en een pad wordt een echo area met Squish message base. }
          { een ! en een pad wordt een echo area met JAM message base.    }
          GetItem (Regel,Item1);
          { verwerken komt zo wel, eerst het record controleren op }
          { al aanwezig zijn, of geen naam hebben ofzo.            }

          { het volgende deel is de naam van de area }
          { Controleer of de naam nog niet bestaat.  }
          GetItem (Regel,Item);

          IF (Item = '') THEN
             Continue;

          { initialiseer een nieuw area record }
          EmptyAreaDataRecord (AreaData);

          AreaData.AreaName_U:=Item;
          AreaData.AreaName_F:=Item;
          AreaData.AreaType:=Area_Echo;
          AreaData.FidoMsgStyle:=NoneType;    { default }
          AreaData.IsInGroups:=ImportInGroup;

          { We hebben nu voldoende informatie om een record naar }
          { disk te kunnen schrijven.                            }
          IndexValue:=GetAreaNameIndexValue (AreaData.AreaName_F);
          AreaBaseRecNr:=GetAreaBaseRecordNrByIndexValue_F (IndexValue);

          { als het record al bestaat, dan pech gehad }
          IF (AreaBaseRecNr <> NILRecordNr) THEN
          BEGIN
               Inc (CursorLine);
               ListAddItem ('Exists:      '+Item,CursorLine,Bottom);
          END ELSE
          BEGIN
               { verwerk nu het eerste item om het record aan te vullen }
               { daarna wordt de area naar disk geschreven.             }
               IF (Item1 = 'P') THEN
               BEGIN
                    { passthrough echo area without message base }
                    Inc (CursorLine);
                    ListAddItem ('No msgbase:  '+Item,CursorLine,Bottom);
               END ELSE
                   CASE Item1[1] OF
                        '0'..'9' :
                              BEGIN
                                   { local area without messagebase }
                                   AreaData.AreaType:=Area_Local;
                                   AreaData.FidoMsgPath:=Item1;
                                   Inc (CursorLine);
                                   ListAddItem ('No msgbase:  '+Item,CursorLine,Bottom);
                              END;

                        '$',
                        '%' : BEGIN
                                   { echo area met squish message base }
                                   Delete (Item1,1,1);
                                   AreaData.FidoMsgStyle:=SquishType;
                                   AreaData.FidoMsgPath:=Item1;
                                   Inc (CursorLine);
                                   ListAddItem ('Squish base: '+Item,CursorLine,Bottom);
                              END;

                        '!' : BEGIN
                                   { echo area met JAM message base }
                                   Delete (Item1,1,1);
                                   AreaData.FidoMsgStyle:=JamType;
                                   AreaData.FidoMsgPath:=Item1;
                                   Inc (CursorLine);
                                   ListAddItem ('JAM base:    '+Item,CursorLine,Bottom);
                              END;

                        ELSE  BEGIN
                                   { echo area met *.MSG message base }
                                   AreaData.FidoMsgStyle:=FidoMsgType;
                                   AreaData.FidoMsgPath:=Item1;
                                   Inc (CursorLine);
                                   ListAddItem ('*.MSG base:  '+Item,CursorLine,Bottom);
                              END;
                   END; { case }

               { bewaar het record op disk }
               AddIndexValueToAreaBaseIndexTable (IndexValue);
               AreaBaseRecNr:=WriteNewAreaBaseRecord (AreaData);
          END;

          { En nu is het prijsschieten op alle nodes die hierop aangesloten }
          { willen worden.                                                  }
          LastAdres:=Config.NodeNrs[1];
          WHILE (Regel <> '') DO
          BEGIN
               GetItem (Regel,Item);

               FidoSplit (Item,NewAdres);
               FidoMergeAdres (LastAdres,NewAdres);

               { probeer of we deze user een area kunnen aansmeren }
               IF FindUserBaseRecordByFidoAddress (NewAdres,UserBaseRecNr) THEN
               BEGIN
                    { Voeg de gebruiker toe aan de lijst met gewillige fans }
                    { van deze area. Mits ie al aangesloten is.             }
                    ReadUserBaseRecord (UserBaseRecNr,UserRec);
                    IF (NOT TestIfAreaIsInUserRec_AreaList (UserRec.AreaList,AreaBaseRecNr)) THEN
                    BEGIN
                         AddUserToAreaSubscrList (AreaData,UserBaseRecNr);
                         WriteAreaBaseRecord (AreaBaseRecNr,AreaData);

                         ReadUserBaseRecord (UserBaseRecNr,UserData);
                         AddAreaToUserSubscrToList (UserData,AreaBaseRecNr);
                         WriteUserBaseRecord (UserBaseRecNr,UserData);

                         Inc (CursorLine);
                         ListAddItem ('  Connected '+Fido2Str (NewAdres),CursorLine,Bottom);
                    END ELSE
                    BEGIN
                         Inc (CursorLine);
                         ListAddItem ('  Already connected: '+Fido2Str (NewAdres),CursorLine,Bottom);
                    END;
               END ELSE
               BEGIN
                    IF (NOT FidoCompare (NewAdres,Config.NodeNrs[1])) THEN
                       ListAddItem ('  Node '+Fido2Str (NewAdres)+' is not in the UserBase',65000,Bottom);
               END;

               LastAdres:=NewAdres;
          END; { while }

          IF (ListItemCount > 0) THEN
          BEGIN
               ListShow (Double,TRUE);
               ListSetCursorOnItem (CursorLine);
               ListUpdateWindow (TRUE,0,CursorLine);
          END;

          IF KeyPressed AND (ReadKey = kEsc) THEN
             Break; { uit de while }

     END; { while }

     JunkAreaBaseIndexTable;   { MD BugFix 031193 }
     JunkUserBaseIndexTable;
     Close (AreasBBS);

     ListAddItem ('',0,Bottom);
     Inc (CursorLine);
     ListAddItem ('Import done. Scroll the list to see the results; Escape/Enter when done ',CursorLine,Bottom);
     ListSetCursorOnItem (CursorLine);
     ListSelect (NoTag,[]);
     ListErase;
END;


{---------------------------------------------------------------------------}
{ WriteAreasBBS                                                             }
{                                                                           }
{ Schrijf een standaard AREAS.BBS file naar disk.                           }
{                                                                           }
PROCEDURE WriteAreasBBS; FAR;

VAR AreasBBS      : TEXT;
    AantalAreas,
    AreaTeller    : AreaBaseRecordNrType;
    Regel         : STRING;
    Search        : SubscrSearchRecord;
    LastUserAdres : FidoAddrType;
    SomeNr        : BYTE;
    Nop           : ValNop;
    IORes         : BYTE;

BEGIN
     Assign (AreasBBS,Path);
     {$I-} ReWrite (AreasBBS); {$I+} IORes:=IOResult;
     PeekFiles;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open file '+Path);
          Exit;
     END;

     IF Desktop THEN
        Message ('Exporting areas, please wait...')
     ELSE
         WriteLn ('Exporting AREAS.BBS ('+Path+')');

     ReadAreaBaseIndexTable;

     { AREAS.BBS Header schrijven }
     WriteLn (AreasBBS,Config.Origins[1]+' ! '+Config.Sysop);
     WriteLn (AreasBBS,';');
     WriteLn (AreasBBS,'; AREAS.BBS');
     WriteLn (AreasBBS,'; '+ FidoCurrTime2Str);
     WriteLn (AreasBBS,';');
     WriteLn (AreasBBS,'; Created by '+DesktopProgramName+' v'+FullProgramVersion);
     WriteLn (AreasBBS,';');

     { doorloop alle areas }
     AantalAreas:=AreaBaseRecCount;

     FOR AreaTeller:=1 TO AantalAreas DO
     BEGIN
          ReadAreaBaseRecord (AreaTeller,AreaData);

          IF (NOT AreaData.Deleted) AND (AreaData.AreaName_F <> '') THEN
          BEGIN
               CASE AreaData.FidoMsgStyle OF
                    NoneType    : BEGIN
                                       Regel:='P'+RepChar (31,' ');
                                       Val (AreaData.FidoMsgPath,SomeNr,Nop);
                                       IF (Nop = 0) THEN
                                          Regel:=AddUpWithSpaces (32,Byte2String (SomeNr));
                                  END;

                    FidoMsgType : Regel:=AddUpWithSpacesNoCut (30,AreaData.FidoMsgPath)+' ';
                    SquishType  : Regel:='$'+AddUpWithSpacesNoCut (30,AreaData.FidoMsgPath)+' ';
                    JAMType     : Regel:='!'+AddUpWithSpacesNoCut (30,AreaData.FidoMsgPath)+' ';
               END; { case }

               Regel:=Regel+AddUpWithSpacesNoCut (30,AreaData.AreaName_F)+' ';

               { Doorloop de lijst met aangesloten gebruikers }
               GetFirstUserSubscribedToThisArea (AreaData.UserList,Search);
               FidoSplit ('0',LastUserAdres );

               WHILE Search.Found DO
               BEGIN
                    ReadUserBaseRecord (Search.UserBaseRecordNr,UserData);
                    IF (UserData.System = _F) THEN
                    BEGIN
                         Regel:=Regel+FidoMinimal (LastUserAdres,UserData.Address)+' ';
                         LastUserAdres:=UserData.Address;
                    END;

                    GetNextUserSubscribedToThisArea( Search );
               END; { while }

               WriteLn (AreasBBS,Regel);
          END; { if not deleted or empty fido area name }
     END; { for areas }

     Close (AreasBBS);
     PeekFiles;
     JunkAreaBaseIndexTable;

     IF Desktop THEN
        WindowPop;
END;


{--------------------------------------------------------------------------}
{ ImportDescriptions                                                       }
{                                                                          }
PROCEDURE ImportDescriptions; FAR;

CONST Xb = 20;
      Yb = 11;
      Xl = 40;
      Yl = 10;

VAR InFile   : TEXT;
    Regel    : STRING;
    P        : BYTE;
    ARecNr   : AreaBaseRecordNrType;
    NewAreas,
    Updated,
    Valids,
    Known    : WORD;
    Keuze    : KeyType;
    AreaName : STRING[MaxLenAreaName];
    IORes    : BYTE;

BEGIN
     Assign (InFile,Path);
     {$I-} Reset (InFile); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          Error ('Cannot open '+Path+' (error '+Byte2String (IORes)+')');
          Exit;
     END;

     MenuDefine (30,(Video.Rows DIV 2)-3,'Create unknown areas?');
     MenuAddItem ('Always');
     MenuAddItem ('Ask on each');
     MenuAddItem ('Never');
     MenuAddItem ('Abort');
     MenuShow;
     MenuSetFirst (1);
     MenuSelect;
     MenuErase;

     IF (Key IN [kEsc,mOpt04]) THEN
     BEGIN
          Close (InFile);
          Exit;
     END;

     Keuze:=Key;

     Message ('Working, please wait...');

     ReadAreaBaseIndexTable;

     Updated:=0;
     Known:=0;
     Valids:=0;
     NewAreas:=0;

     WHILE (NOT Eof (InFile)) DO
     BEGIN
          ReadLn (InFile,Regel);

          IF (Regel = '') OR (NOT (Regel[1] IN ['A'..'Z','0'..'9'])) THEN
             Continue;

          Regel:=CleanTabs (Regel,1);

          P:=Pos (' ',Regel);

          IF (P = 0) THEN
             Continue;

          { extract the two fields }
          AreaName:=UpCaseString (Copy (Regel,1,P-1));
          Delete (Regel,1,P);
          Regel:=DeleteFrontAndBackSpaces (Regel);
          Regel:=Copy (Regel,1,MaxLenComment);

          IF (Regel = '') THEN
             Continue;

          Inc (Valids);

          ARecNr:=GetAreaBaseRecordNrByAreaName_F (AreaName);

          IF (ARecNr = NILRecordNr) THEN
          BEGIN
               IF (Keuze = mOpt03{never}) THEN
                  Continue;

               IF (Keuze = mOpt02{ask}) THEN
               BEGIN
                    MenuDefine (30,(Video.Rows DIV 2)-3,'Create area '+AreaName);
                    MenuAddItem ('Always');
                    MenuAddItem ('Yes');
                    MenuAddItem ('No');
                    MenuAddItem ('Never');
                    MenuAddItem ('Abort');
                    MenuShow;
                    MenuSetFirst (1);
                    MenuSelect;
                    MenuErase;

                    CASE Key OF
                         mOpt01:
                             Keuze:=mOpt01;

                         mOpt02:
                             {yes};

                         kEsc,
                         mOpt03:
                             Continue;

                         mOpt04:
                             Keuze:=mOpt03;

                         mOpt05:
                             BEGIN
                                  Close (InFile);
                                  Break;
                             END;
                    END; { case }
               END;

               { ask=yes or always: aanmaken }
               EmptyAreaDataRecord (AreaData);

               AreaData.AreaName_F:=AreaName;
               AreaData.AreaName_U:=AreaName;
               AddGroupToGroupList (AreaData.IsInGroups,MaxGroups);

               AreaData.Comment:=Regel;

               WriteNewAreaBaseRecord (AreaData);

               Inc (NewAreas);

               Continue;
          END;

          Inc (Known);

          ReadAreaBaseRecord (ARecNr,AreaData);

          IF (AreaData.Comment <> Regel) THEN
          BEGIN
               AreaData.Comment:=Regel;
               WriteAreaBaseRecord (ARecNr,AreaData);
               Inc (Updated);
          END;

     END; { while }

     JunkAreaBaseIndexTable;
     Close (InFile);

     WindowPop;

     WindowPush (Xb,Yb,Xl,Yl);
     BoxDraw (Double,Xb,Yb,Xl,Yl);

     WriteXY (Xb+2,Yb+1,'Import results');

     WriteXY (Xb+2,Yb+3,'Descriptions found:');
     WriteXY (Xb+2,Yb+4,'Of which known areas:');
     WriteXY (Xb+2,Yb+5,'Of which were updated:');

     WriteXY (Xb+2,Yb+7,'Newly created areas:');
     WriteXY (Xb+2,Yb+8,'New areas were put in group Z3');

     WriteXYC (Xb+25,Yb+3,cBoxData,Word2String (Valids));
     WriteXY (Xb+25,Yb+4,Word2String (Known));
     WriteXY (Xb+25,Yb+5,Word2String (Updated));
     WriteXY (Xb+25,Yb+7,Word2String (NewAreas));

     PushKeysLine;
     WriteKeysLine (' Press any key');
     ReadKey;
     PopKeysLine;
     WindowPop;
END;


{--------------------------------------------------------------------------}
{ ImportAreaDescriptions                                                   }
{                                                                          }
{ Deze import routine verwacht een textfile met op iedere regel een area   }
{ naam, een of meer spaties of tabs en dan een description. De description }
{ wordt in de area beschrijving opgenomen. De areas zelf worden niet       }
{ aangemaakt.                                                              }
{                                                                          }
PROCEDURE ImportAreaDescriptions;
BEGIN
     RequestHelp (htr_ImpExp_FIDONET_NA);
     EnterAndImport (TRUE{import},'FIDONET.NA',ImportDescriptions,9);
END;


{--------------------------------------------------------------------------}
{ ExportAreasBBS                                                           }
{                                                                          }
PROCEDURE ExportAREASBBS (Param : STRING);
BEGIN
     IF (Param = '') THEN
     BEGIN
          Desktop:=TRUE;
          EnterAndImport (FALSE,'AREAS.BBS',WriteAREASBBS,1)
     END
     ELSE BEGIN
          Desktop:=FALSE;
          Path:=Param;
          WriteAREASBBS;
     END;

    {EnterAndImport ( FALSE , 'AREAS.BBS',WriteAREASBBS);}
END;


{--------------------------------------------------------------------------}
{ ImportExportMenu                                                         }
{                                                                          }
{ Deze routine laat het import/export menu zien en laat een keuze maken.   }
{ Escape keert terug naar het hoofdmenu.                                   }
{                                                                          }
PROCEDURE ImportExportMenu;

VAR Quit : BOOLEAN;

BEGIN
     MenuDefine (3,3,'Import / Export menu');
     MenuAddItem ('Import AREAS.BBS file');
     MenuAddItem ('Export AREAS.BBS file');
     MenuAddItem ('Import GEcho nodes file');
     MenuAddItem ('Import GEcho areas file');
     MenuAddItem ('Import nodes from FastEcho config');
     MenuAddItem ('Import areas from FastEcho config');
     MenuAddItem ('Import Usenet NEWSGROUPS file');
     MenuAddItem ('Import Waffle SYSTEMS file');
     MenuAddItem ('Import Usenet PATHS file');
     MenuAddItem ('Import UUCICO FEEDS file');
     MenuAddItem ('Import Squish like area config');
     MenuAddItem ('Export Squish like area config');
     MenuAddItem ('Import Area Descriptions');
{    MenuAddItem ('Export configuration to text file');}
     MenuSetHelp (htr_ImpExp_Menu);
     MenuShow;

     Quit:=FALSE;
     REPEAT
           CASE MenuSelect OF
                mOpt01 : EnterAndImport (TRUE,'AREAS.BBS',ReadAREASBBS,1);
                mOpt02 : ExportAREASBBS ('');
                mOpt03 : EnterAndImport (TRUE,'GECHO\NODEFILE.GE',ReadGEchoNodeFile,2);
                mOpt04 : EnterAndImport (TRUE,'GECHO\AREAFILE.GE',ReadGEchoAreaFile,3);
                mOpt05 : EnterAndImport (TRUE,'FE\FASTECHO.CFG',ReadFastEchoNodes,4);
                mOpt06 : EnterAndImport (TRUE,'FE\FASTECHO.CFG',ReadFastEchoAreas,4);
                mOpt07 : EnterAndImport (TRUE,'WAFFLE\USENET',ReadUsenetNewsgroupsFile,5);
                mOpt08 : EnterAndImport (TRUE,'WAFFLE\SYSTEMS',ReadWaffleSystemsFile,5);
                mOpt09 : EnterAndImport (TRUE,'WAFFLE\PATHS',ReadUsenetPathsFile,6);
                mOpt10 : EnterAndImport (TRUE,'WAFFLE\FEEDS',ReadUUCicoFeedsFile,7);
                mOpt11 : EnterAndImport (TRUE,'SQUISH.CFG',ReadSquishConfig,8);
                mOpt12 : ExportSquishConfig ('');
                mOpt13 : ImportAreaDescriptions;
               {mOpt14 : WriteConfiguration ('Hellup.Txt');}
                kEsc   : Quit:=TRUE;
           END; { case }
     UNTIL Quit;

     MenuErase;
END;


BEGIN
     Path:='';
     PathType:=255;
     Desktop:=FALSE;
END.
