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

{$i platform.inc}

{ Routines om de Areas Databases te editten vanuit WtrConf }

{ History

RvdW 20-02-93 Deze unit afgesplitst uit wtrconf.pas
     26-03-93 DeleteAreaBaseRecord aangepast zodat bij het verwijderen van
              een area eerst de subscribed users geunsubscribed worden,
              zowel vanaf de area als de users kant. Door deze bug werden
              de messages waarschijnlijk meerdere keren weggeschreven.
     27-03-93 Velden Moderated en Moderator toegevoegd.
     30-03-93 AutoCreateArea toegevoegd.
     02-04-93 Bij EmptyAreaDataRecord wordt nu default de eerste systeem
              origin ingesteld ipv de custom origin.
     03-04-93 Zelfde bugje als in de UserBase opgelost bij het aanmaken van
              een nieuwe area.
     03-04-93 Vanaf nu kunnen in een group meerdere areas getagged worden
              waarna door een druk op enter (normaal is dit Edit) al die
              areas in een andere group gestopt kunnen worden.
     16-05-93 Bij het toevoegen van not yet subscribed users werd gekeken
              naar het AreaFilter. Nu naar de AreaData.IsInGroups filter.
              Op deze manier kan een area verhuisd worden en meteen de juiste
              mensen toegevoegd worden.
MD   18-06-93 Toevoegen van support voor de Fido *.MSG areas
     26-06-93 Toevoegen van MsgAge en MsgLimits per area
     08-09-93 $IFDEF WtrConf toegevoegd, scheelt in compileer tijd en
              bied overzicht wie wat gebruikt.
     01-11-93 Automatische gecreerde areas kunnen nu ook een lokale base
              toegewezen krijgen... scheelt nog meer type werk !
              Nieuwe areas krijgen automatisch een correct AKA toegewezen
              Bij wijzigingen van een area wordt er nu gevraagt of
              de area bewaard moet worden.
     15-11-93 Er wordt bij het verwijderen van areas nu ook gevraagt of
              je de Message base file wilt verwijderen.
     01-12-93 Plaats een DELETED vlag op elk temporary record dat niet
              meer gebruikt wordt.
     28-06-94 AreaRecord Editor springt niet meteen terug meer naar
              het hoofdmenu
}

INTERFACE

USES Database;

{$IFDEF WtrConf}
FUNCTION  EditAreaBaseRecord (RecNr : AreaBaseRecordNrType) : BOOLEAN;
PROCEDURE DeleteAreaBaseRecord (RecNr : AreaBaseRecordNrType; KillBase,RapidDelete : BOOLEAN);
PROCEDURE AreaConfigs;
{$ENDIF}

PROCEDURE EmptyAreaDataRecord (VAR AreaRec : AreaBaseRecord);
FUNCTION  AutoCreateArea (AreaName : AreaNameString; NewPath : STRING) : AreaBaseRecordNrType;

VAR AreaData                 : AreaBaseRecord;
    AreaCreatorUserBaseRecNr : UserBaseRecordNrType;
    NewAreasCreated          : WORD;


IMPLEMENTATION

USES Ramon,
     Dos,
     Logs,
     Globals,
     Fido,
     Cfg,
     Tdb,
     AreaMgr,
     UnixTime,
     CharSets;

{$I WTRHLP.INC}

{$IFDEF WtrConf}
VAR AreaRecNr       : AreaBaseRecordNrType;                   { voor saven }
    AreaFilter      : GroupFlagType;                  { toegestane groepen }
    OriginDesc      : STRING[MaxLenOrigin];
    OriginAkaStr    : STRING[MaxLenFidoAddrString];
    ModeratorDesc   : STRING[MaxLenModerator];
    FidoMsgAgeStr,
    FidoMsgLimitStr : STRING[5];  { WordString, maar niet onder OS2 }
    OldAreaData     : AreaBaseRecord;
    CurrMsgBasePath : PathStr;
    DupeHistoryStr  : STRING[3];
    FTNCharSetDescr,
    RFCCharSetDescr : STRING[30];

{--------------------------------------------------------------------------}
{ FixAreaDataRecord                                                        }
{                                                                          }
{ Deze routine moet gebruikt worden om een zojuist ingelezen of leeg       }
{ gemaakt record af te maken. Alle velden worden op lengte gemaakt zodat   }
{ de FieldDefine* routine niet gaan kankeren.                              }
{                                                                          }
PROCEDURE FixAreaDataRecord (VAR AreaRec : AreaBaseRecord);
BEGIN
     WITH AreaRec DO
     BEGIN
          AreaName_F:=AddUpWithSpaces (MaxLenAreaName,UpCaseString (AreaName_F));
          AreaName_U:=AddUpWithSpaces (MaxLenAreaName,LoCaseString (AreaName_U));
          Comment:=AddUpWithSpaces (MaxLenComment,Comment);
          GroupListDesc:=AddUpWithSpaces (55,BuildGroupListDesc (AreaData.IsInGroups,55));
          Origin:=AddUpWithSpaces (MaxLenOrigin,Origin);

          IF (OriginNr = 0) THEN OriginDesc:=AreaData.Origin
                            ELSE OriginDesc:=Config.Origins[OriginNr];
          OriginDesc:=AddUpWithSpaces (MaxLenOrigin,OriginDesc);

          OriginAkaStr:=AddUpWithSpaces (MaxLenFidoAddrString,Fido2Str (Config.NodeNrs[OriginAka]));

          FidoMsgAgeStr:=AddUpWithSpaces (5,Word2String (FidoMsgAge));
          FidoMsgLimitStr:=AddUpWithSpaces (5,Word2String (FidoMsgLimit));

          IF (AreaData.Moderated = mdNONE) THEN
             ModeratorDesc:='Not moderated'
          ELSE
              IF (DeleteFrontAndBackSpaces (AreaData.Moderator) = '') THEN
                 ModeratorDesc:='Automatic via backbone'
              ELSE
                  ModeratorDesc:=AreaData.Moderator;
          ModeratorDesc:=AddUpWithSpaces (MaxLenModerator,ModeratorDesc);

          Moderator:=AddUpWithSpaces (MaxLenModerator,Moderator);
          FidoMsgPath:=AddUpWithSpaces (MaxLenPath,FidoMsgPath);
          DecodePath:=AddUpWithSpaces (MaxLenPath,DecodePath);
          RulesFile:=AddUpWithSpaces (MaxLenPath,RulesFile);
          DupeHistoryStr:=AddUpWithSpaces (3,Byte2String (DupeAge));

          FTNCharSetDescr:=AddUpWithSpaces (30,CharSet_FTN);
          RFCCharSetDescr:=AddUpWithSpaces (30,CharSet_RFC);
     END; { with }
END;
{$ENDIF (WtrConf)}


{--------------------------------------------------------------------------}
{ EmptyAreaDataRecord                                                      }
{                                                                          }
{ Deze routine maakt het AreaData record leeg.                             }
{                                                                          }
PROCEDURE EmptyAreaDataRecord (VAR AreaRec : AreaBaseRecord);
BEGIN
     { RWI 960320: nog legere records }
     FillChar (AreaRec,SizeOf (AreaBaseRecord),0);

     WITH AreaRec DO
     BEGIN
          { global }
          Deleted:=FALSE;
          AreaName_F:='';
          AreaName_U:='';
          AreaType:=Area_Echo;
          Comment:='';
          ResetGroupFlags (IsInGroups); { no groups }
          UserList:=NILRecordNr; { (nog) geen record in SubscriptDatabase }

          { fido }
          SetSingleSeenByBit (AddSeenByAkas,1);

          FidoMsgStyle:=NONETYPE;
          FidoMsgPath:=Config.DefaultFidoMsgPath;
          FidoMsgAge:=Config.DefDaysToKeep_F;
          FidoMsgLimit:=Config.DefNumbToKeep_F;
          Passive:=FALSE;
          AllowPassive:=TRUE;

          { import from usenet }
          OriginNr:=1; { default: first system origin }
          Origin:='';
          OriginAka:=1; { default: main aka }

          { usenet }
          Moderated:=mdNONE;
          Moderator:='';

          { MIME / XX/UU-decode }
          Decode:=FALSE;
          DecodePath:='';

          Mandatory:=FALSE;  { areafix/newsfix }

          RulesFile:='';

          DupeList:=0; { no section yet }
          DupeAge:=2;  { keep two weeks of dupes }
     END;

     {$IFDEF WtrConf}
     FixAreaDataRecord (AreaRec);
     {$ENDIF}
END;


{--------------------------------------------------------------------------}
{ AutoCreateArea                                                           }
{                                                                          }
{ Deze routine maakt helemaal zelfstandig een nieuwe area aan en stopt     }
{ deze in group Z1. Hierdoor is het mogelijk nieuwe areas die wel          }
{ binnenkomen, maar nog niet gecreerd zijn toch op te nemen zonder al te   }
{ veel tikwerk.                                                            }
{ Teruggegeven wordt het AreaBaseRecordNr van het nieuw aangemaakte record }
{ zodat een extra call naar GetAreaBaseRecordNrByAreaName (die de aangaf   }
{ dat de area niet bestond) niet meer nodig is.                            }
{ De inhoud van het record komt ook meteen in AreaData te zitten, zodat    }
{ het record eigenlijk niet ingelezen hoeft te worden.                     }
{ In de globaal gedefinieerde variabele AreaCreaterUserBaseRecNr moet het  }
{ UserBase record nummer staan van de user die deze area geleverd heeft.   }
{ Deze wordt als enige op de area aangesloten, zodat meteen bekend is wie  }
{ de area aangemaakt heeft.                                                }
{ In verband met de ConnectArea aanroep is het van belang dat de AreaBase  }
{ en UserBase records in kwestie naar disk zijn geschreven voor de aanroep }
{ naar deze routine en dat ze achteraf opnieuw ingelezen worden.           }
{                                                                          }
FUNCTION AutoCreateArea (AreaName : AreaNameString; NewPath : STRING) : AreaBaseRecordNrType;

VAR TmpName  : LONGINT;
    UserData : UserBaseRecord;
    Dummy    : FidoAddrType;
    IORes    : BYTE;

BEGIN
     EmptyAreaDataRecord (AreaData);

     AreaData.AreaName_F:=UpCaseString (DeleteBackSpaces (AreaName));
     AreaData.AreaName_U:=LoCaseString (AreaData.AreaName_F);
     AreaData.Comment:='Auto created on '+UnixTimeToString (GetCurrentUnixTime)+
                       ', delivered by ';
     ResetGroupFlags (AreaData.IsInGroups);
     AddGroupToGroupList (AreaData.IsInGroups,Group_NewAreas);

     { Kijk of we een nieuwe lokale area moeten creeren }
     IF (Config.FidoAutoCreateType <> NoneType) THEN
     BEGIN
          TmpName:=UpdateCRC32 ($FFFFFFFF,AreaData.AreaName_F[1],Length (AreaData.AreaName_F));
          AreaData.FidoMsgStyle:=Config.FidoAutoCreateType;

          IF (NewPath = '') THEN
             AreaData.FidoMsgPath:=DeleteBackSpaces (Config.DefaultFidoMsgPath)
          ELSE
              AreaData.FidoMsgPath:=NewPath;

          { er moet altijd een backslash aan het einde van het pad staan }
          IF (AreaData.FidoMsgPath[Length (AreaData.FidoMsgPath)] <> '\') THEN
             AreaData.FidoMsgPath:=AreaData.FidoMsgPath+'\';

          IORes:=CreatePath (AreaData.FidoMsgPath);
          IF (IORes <> 0) THEN
          BEGIN
               LogDiskIOError (IORes,'Could not create directory for new msgbase!');
               LogExtraMessage (AreaData.FidoMsgPath);
          END;

          AreaData.FidoMsgPath:=AreaData.FidoMsgPath+Long2HexString (TmpName);

          IF (Config.FidoAutoCreateType = FidoMsgType) THEN
          BEGIN
               AreaData.FidoMsgPath:=AreaData.FidoMsgPath+'\';
               { deze directory ook meteen aanmaken }
               IORes:=CreatePath (AreaData.FidoMsgPath);
               IF (IORes <> 0) THEN
               BEGIN
                    LogDiskIOError (IORes,'Could not create sub-directory for *.MSG base');
                    LogExtraMessage (AreaData.FidoMsgPath);
               END;
          END;
     END;

     { Probeer het adres aan te passen aan de zender }
     ReadUserBaseRecord (AreaCreatorUserBaseRecNr,UserData);
     CASE UserData.System OF
          _F : BEGIN
                    AreaData.OriginAKA:=FidoMatchAdres (UserData.Address,Dummy);
                    SetSingleSeenByBit (AreaData.AddSeenByAkas,AreaData.OriginAKA);
                    AreaData.Comment:=AreaData.Comment+Fido2Str (UserData.Address);
               END;

          _SOUP,
          _B,
          _U : AreaData.Comment:=AreaData.Comment+UserData.UUCPName;

          ELSE AreaData.Comment:=AreaData.Comment+'??';
     END; { case }

     AddIndexValueToAreaBaseIndexTable (GetAreaNameIndexValue (AreaData.AreaName_F));
     AutoCreateArea:=AreaBaseRecCount+1;

     WriteNewAreaBaseRecord (AreaData);
     ConnectArea (AreaBaseRecCount,AreaCreatorUserBaseRecNr);

     Inc (NewAreasCreated);
END;

{$IFDEF WtrConf}
{--------------------------------------------------------------------------}
{ Alle routines onder deze lijn zijn alleen voor WtrConf beschikbaar       }
{--------------------------------------------------------------------------}

{--------------------------------------------------------------------------}
{ EditAreaGroupsList                                                       }
{                                                                          }
{ Met deze routine kan het AreaData.IsInGroups veld gewijzigd worden.      }
{                                                                          }
PROCEDURE EditAreaGroupsList; FAR;
BEGIN
     WHILE TRUE DO
     BEGIN
          EditGroupsList (AreaData.IsInGroups,
                          'Area is in these groups',
                          '<area is in no groups>',
                          htr_AreaEdit_AllowedGroups,
                          htr_AreaEdit_NotYetAllowedGroups);

          IF TestGroupListIsEmpty (AreaData.IsInGroups) THEN
             Error ('Area must be in at least 1 group !')
          ELSE
              Exit;
     END;
END;


{--------------------------------------------------------------------------}
{ EditAreaSubscrList                                                       }
{                                                                          }
{ Met deze routine kunnen de aan de area geSubscribed users aangepast      }
{ worden. Is aangesloten via de FieldDefineList. In AreaData staan de      }
{ gegevens van de gekozen Area. Deze mogen NIET gewijzigd worden.          }
{                                                                          }
{ RvdW 16-05-93: Bij het toevoegen van not yet subscribed users werd       }
{                de userbase doorlopen en mensen met het AreaFilter die    }
{                nog niet waren aangesloten in de lijst gezet. Nu wordt    }
{                gekeken naar het AreaData.IsInGroups filter. Als de group }
{                dan in een andere area gestopt wordt door Groups te       }
{                veranderen, dan kunnen meteen de mensen erbij gezocht     }
{                worden.                                                   }
{                                                                          }
PROCEDURE EditAreaSubscrList; FAR;

VAR Quit,
    Quit2    : BOOLEAN;
    Search   : SubscrSearchRecord;
    UserData : UserBaseRecord;
    Lp,
    Keuze2,
    Keuze    : WORD;
    Lp2      : UserBaseRecordNrType;

    {----------------------------------------------------------------------}
    { GetUserDescr                                                         }
    {                                                                      }
    { Deze routine bouwt de omschrijving op van het user record dat op dit }
    { moment in UserData staat.                                            }
    {                                                                      }
    FUNCTION GetUserDescr : STRING;
    BEGIN
          CASE UserData.System OF
               _F :
                   GetUserDescr:=Fido2Str (UserData.Address)+
                                  ' ('+DeleteBackSpaces (UserData.SysOp)+') ';

               _U,
               _B,
               _SOUP :
                   GetUserDescr:=DeleteBackSpaces (UserData.UUCPName)+
                                 ' ('+UserData.Organization+') ';

               _BBS :
                   GetUserDescr:=Word2String (UserData.FakeZone)+':'+
                                 Word2String (UserData.FakeNet)+'/'+
                                 Word2String (UserData.FakeNode)+
                                 ' ('+UserData.Organization+') ';

          END; { case }
    END;

BEGIN
     ListDefine (3,3,Video.Cols-20,Video.Rows-4,Default,
                 'Subscribed users to this area',
                 htr_AreaEdit_SubscribedUsers);

     GetFirstUserSubscribedToThisArea (AreaData.UserList,Search);
     WHILE Search.Found DO
     BEGIN
          ReadUserBaseRecord (Search.UserBaseRecordNr,UserData);
          ListAddItem (GetUserDescr,Search.UserBaseRecordNr,Sorted);
          GetNextUserSubscribedToThisArea (Search);
     END; { while }

     Quit:=FALSE;
     REPEAT
           IF (ListItemCount = 0) THEN
              ListAddItem ('<no subscribed users>',65534,Bottom);

           Keuze:=ListSelect (DoTag,[kIns,kDel]);

           ListRemoveItem (65534);

           CASE Key OF
                kEsc : Quit:=TRUE;

                kIns : BEGIN
                            ListDefine (Video.Cols-2,3,Video.Cols-20,Video.Rows-4,TopRight,
                                        'Not yet subscribed users',
                                        htr_AreaEdit_NotYetSubscribedUsers);

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

                                 { RvdW 16-05-93: Groups vergelijking aangepast }
                                 IF (NOT UserData.Deleted) AND
                                    (TestIfGroupCommon (UserData.Groups,AreaData.IsInGroups)) AND
                                    (NOT TestIfUserIsInAreaRec_UserList (AreaData.UserList,Lp))
                                 THEN
                                     ListAddItem (GetUserDescr,Lp,Sorted);
                            END; { lp }

                            IF (ListItemCount = 0) THEN
                               ListAddItem ('<all users already subscribed this area>',65534,Bottom);

                            Quit2:=FALSE;
                            REPEAT
                                  Keuze2:=ListSelect (DoTag,[]);

                                  CASE Key OF
                                       kEsc : Quit2:=TRUE;

                                       kRet : BEGIN
                                                   IF (ListTagCount = 0) THEN
                                                   BEGIN
                                                        AddUserToAreaSubscrList (AreaData,Keuze2);

                                                        ReadUserBaseRecord (Keuze2,UserData);
                                                        AddAreaToUserSubscrToList (UserData,AreaRecNr);
                                                        WriteUserBaseRecord (Keuze2,UserData);

                                                        ListAddItemToPrevList (GetUserDescr,Keuze2,Sorted);
                                                   END ELSE
                                                       FOR Lp:=1 TO ListTagCount DO
                                                       BEGIN
                                                            Keuze2:=ListGetTaggedItemNr (Lp);

                                                            AddUserToAreaSubscrList (AreaData,Keuze2);

                                                            ReadUserBaseRecord (Keuze2,UserData);
                                                            AddAreaToUserSubscrToList (UserData,AreaRecNr);
                                                            WriteUserBaseRecord (Keuze2,UserData);

                                                            ListAddItemToPrevList (GetUserDescr,Keuze2,Sorted);
                                                       END; { for }

                                                   WriteAreaBaseRecord (AreaRecNr,AreaData);

                                                   Quit2:=TRUE;
                                              END;
                                  END; { case }
                            UNTIL Quit2;

                            ListErase;
                       END; { kIns }

                kDel : BEGIN
                            IF (ListTagCount = 0) THEN
                            BEGIN
                                 IF (Keuze < 65000) AND (AreYouSure ('Unsubscribe this user?') = mOpt01) THEN
                                 BEGIN
                                      RemoveUserFromAreaSubscrList (AreaData,Keuze);

                                      ReadUserBaseRecord (Keuze,UserData);
                                      RemoveAreaFromUserSubscrToList (UserData,AreaRecNr);
                                      WriteUserBaseRecord (Keuze,UserData);

                                      ListRemoveItem (Keuze);
                                 END;
                            END ELSE
                            BEGIN
                                 IF (AreYouSure ('Unsubscribe these users?') = mOpt01) THEN
                                    WHILE (ListTagCount > 0) DO
                                    BEGIN
                                         Keuze:=ListGetTaggedItemNr (1);

                                         RemoveUserFromAreaSubscrList (AreaData,Keuze);

                                         ReadUserBaseRecord (Keuze,UserData);
                                         RemoveAreaFromUserSubscrToList (UserData,AreaRecNr);
                                         WriteUserBaseRecord (Keuze,UserData);

                                         ListRemoveItem (Keuze);
                                    END; { while }
                            END;

                            WriteAreaBaseRecord (AreaRecNr,AreaData);

                       END; { kDel }
           END; { case }

     UNTIL Quit;

     ListErase;
END;


{--------------------------------------------------------------------------}
{ GrayOriginField                                                          }
{                                                                          }
PROCEDURE GrayOriginField; FAR;
BEGIN
     IF (AreaData.AreaType <> Area_Local) THEN
        FieldEnableField (11)
     ELSE
         FieldDisableField (11);

     FieldUpdateOneField (11);
END;


{--------------------------------------------------------------------------}
{ EditAreaOrigin                                                           }
{                                                                          }
{ Met deze routine kan een van de standaard origin lines uitgekozen worden }
{ als default origin nummer.                                               }
{                                                                          }
PROCEDURE EditAreaOrigin; FAR;

CONST Xb = 4;
      Yb = 10;
      Xl = 75;
      Yl = 7;

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

     FieldPushAll;
     FieldInit;

     WriteXY (Xb+2,Yb+1,'Origin');
     FieldAutoDefineToggles (Xb+12,Yb+1,AreaData.OriginNr,'custom|system 1|system 2',0);
     FieldSetHelp (0,htr_AreaEdit_EditOrigin);

     WriteXY (Xb+2,Yb+2,'Custom');
     FieldAutoDefineOne (Xb+12,Yb+2,@AreaData.Origin,RepChar (MaxLenOrigin,'$'));
     FieldSetHelp (0,htr_AreaEdit_CustomOrigin);

     WriteXY (Xb+2,Yb+4,'System 1:');
     WriteXY (Xb+12,Yb+4,Config.Origins[1]);

     WriteXY (Xb+2,Yb+5,'System 2:');
     WriteXY (Xb+12,Yb+5,Config.Origins[2]);

     IF (AreaData.OriginNr = 0) THEN
        FieldSetFirst (2);

     FieldEdit;

     FieldPopAll;
     WindowPop;

     FixAreaDataRecord (AreaData);
     GrayOriginField;
END;


{--------------------------------------------------------------------------}
{ GrayModeratorField                                                       }
{                                                                          }
PROCEDURE GrayModeratorField; FAR;
BEGIN
     IF (AreaData.Moderated = mdNONE) THEN
        FieldDisableField (2)
     ELSE
         FieldEnableField (2);

     FieldUpdateOneField (2);
END;


{--------------------------------------------------------------------------}
{ EditAreaModeration                                                       }
{                                                                          }
{ This routine is called to editor the moderator of this area.             }
{                                                                          }
PROCEDURE EditAreaModeration; FAR;

CONST Xb = 10;
      Yb = 15;
      Xl = 64;
      Yl = 4;

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

     FieldPushAll;
     FieldInit;

     WriteXY (Xb+2,Yb+1,'Moderated');
     FieldAutoDefineTogglesCall (Xb+12,Yb+1,AreaData.Moderated,'not|e-mail',0,GrayModeratorField);
     FieldSetHelp (0,htr_AreaEdit_Moderated);

     WriteXY (Xb+2,Yb+2,'E-mail');
     FieldAutoDefineOne (Xb+12,Yb+2,@AreaData.Moderator,RepChar (50,'$'));
     FieldSetHelp (0,htr_AreaEdit_ModeratorEmail);

     GrayModeratorField;
     FieldEdit;

     FieldPopAll;
     WindowPop;

     FixAreaDataRecord (AreaData);
END;


{--------------------------------------------------------------------------}
{ EditAreaAddSeenByList                                                    }
{                                                                          }
{ Met deze routine kan de lijst van SEEN-BY's die toegevoegd wordt aan de  }
{ seenby regel van een bericht, worden gewijzigd. Voor iedere AKA die er   }
{ is wordt er een bitje gezet of gereset in de AreaData.AddSeenBys var.    }
{                                                                          }
PROCEDURE EditAreaAddSeenByList; FAR;

VAR Lp     : BYTE;
    Quit,
    Quit2  : BOOLEAN;
    Keuze,
    Keuze2 : WORD;

BEGIN
     ListDefine (3,3,39,Video.Rows-4,Default,
                 'AKAs that are added to the SEEN-BY',
                 htr_AreaEdit_SEENBYs_list);

     ListSetConvertRoutine (FidoAkaListConvertFunc);

     FOR Lp:=1 TO MaxAKAs DO
         IF HasSeenByBit (AreaData.AddSeenByAkas,Lp) THEN
            ListAddItem (Fido2Str (Config.NodeNrs[Lp]),Lp,Convert);

     Quit:=FALSE;
     REPEAT
           IF (ListItemCount = 0) THEN
              ListAddItem ('<no AKAs are added>',65534,Bottom);

           Keuze:=ListSelect (DoTag,[kIns,kDel,kF10]);

           ListRemoveItem (65534);

           CASE Key OF
                kF10,
                kEsc : Quit:=TRUE;

                kDel : BEGIN
                            IF (ListTagCount = 0) THEN
                            BEGIN
                                 IF (Keuze < 65000) AND (AreYouSure ('Remove this AKA?') = mOpt01) THEN
                                 BEGIN
                                      ResetSeenByBit (AreaData.AddSeenByAkas,Keuze);
                                      ListRemoveItem (Keuze);
                                 END;
                            END ELSE
                                IF (AreYouSure ('Remove these AKAs?') = mOpt01) THEN
                                   WHILE (ListTagCount > 0) DO
                                   BEGIN
                                        Keuze:=ListGetTaggedItemNr (1);
                                        ResetSeenByBit (AreaData.AddSeenByAkas,Keuze);
                                        ListRemoveItem (Keuze);
                                   END; { for }
                        END; { kDel }

                kIns : BEGIN
                            ListDefine (Video.Cols-2,3,39,Video.Rows-4,TopRight,
                                        'AKAs that are not added yet',
                                        htr_AreaEdit_Add_SEENBYs_list);

                            ListSetConvertRoutine (FidoAkaListConvertFunc);

                            FOR Lp:=1 TO MaxAKAs DO
                                IF (NOT HasSeenByBit (AreaData.AddSeenByAkas,Lp)) THEN
                                   IF (Fido2Str (Config.NodeNrs[Lp]) <> '0') THEN
                                      ListAddItem (Fido2Str (Config.NodeNrs[Lp]),Lp,Convert);

                            IF (ListItemCount = 0) THEN
                               ListAddItem ('<all AKAs are added already>',65534,Bottom);

                            Quit2:=FALSE;
                            REPEAT
                                  Keuze2:=ListSelect (DoTag,[]);

                                  CASE Key OF
                                       kEsc : BEGIN
                                                   ListErase;
                                                   Quit2:=TRUE;
                                              END;

                                       kRet : BEGIN
                                                   IF (ListTagCount = 0) THEN
                                                   BEGIN
                                                        SetSeenByBit (AreaData.AddSeenByAkas,Keuze2);
                                                        ListAddItemToPrevList (Fido2Str (Config.NodeNrs[Keuze2]),
                                                                              Keuze2,Convert);
                                                   END ELSE
                                                       FOR Lp:=1 TO ListTagCount DO
                                                       BEGIN
                                                            Keuze2:=ListGetTaggedItemNr (Lp);
                                                            SetSeenByBit (AreaData.AddSeenByAkas,Keuze2);
                                                            ListAddItemToPrevList (Fido2Str (Config.NodeNrs[Keuze2]),
                                                                                   Keuze2,Convert);
                                                       END; { while }

                                                   ListErase;
                                                   ListSetCursorOnItem (Keuze2);
                                                   Quit2:=TRUE;
                                              END;
                                  END; { case }
                            UNTIL Quit2;
                       END; { kIns }
           END; { case }
     UNTIL Quit;

     ListErase;
END;


{--------------------------------------------------------------------------}
{ EditAreaOriginAka                                                        }
{                                                                          }
{ Met deze routine kan een van de AKAs uitgekozen worden als Origin AKA.   }
{                                                                          }
PROCEDURE EditAreaOriginAka; FAR;

VAR AkaLp : 1..MaxAkas;
    Keuze : WORD;
    Quit  : BOOLEAN;

BEGIN
     ListDefine (38,3,39,Video.Rows-4,Default,
                 'Select an Origin AKA',
                 htr_AreaEdit_Select_Origin_AKA);

     ListSetConvertRoutine (FidoAkaListConvertFunc);

     FOR AkaLp:=1 TO MaxAKAs DO
         IF (Fido2Str (Config.NodeNrs[AkaLp]) <> '0') THEN
            ListAddItem (Fido2Str (Config.NodeNrs[AkaLp]),AkaLp,Convert);

     { RWI 960601 }
     ListSetCursorOnItem (AreaData.OriginAKA);

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

           CASE Key OF
                kEsc : Quit:=TRUE;

                kRet : BEGIN
                            AreaData.OriginAka:=Keuze;
                            IF (NOT IsOnlySeenByBit (AreaData.AddSeenByAkas,Keuze)) THEN
                            BEGIN
                                 SetSingleSeenByBit (AreaData.AddSeenByAkas,Keuze);
                                 Error ('Note: SEEN-BY AKAs have been reset to '+Fido2Str (Config.NodeNrs[Keuze])+' only!');
                            END;

                            FixAreaDataRecord (AreaData);
                            Quit:=TRUE;
                       END;
           END; { case }
     UNTIL Quit;

     ListErase;
END;


{--------------------------------------------------------------------------}
{ CheckAreaName                                                            }
{                                                                          }
{ Zorg ervoor dat je een areanaam niet 2x hoeft in te voeren.              }
{                                                                          }
FUNCTION CheckAreaName (Buffer : StringPtr) : BOOLEAN; FAR;
BEGIN
     WITH AreaData DO
     BEGIN
          AreaName_F:=DeleteFrontAndBackSpaces (AreaName_F);
          AreaName_U:=DeleteFrontAndBackSpaces (AreaName_U);

          IF (AreaName_U = '') THEN AreaName_U:=LoCaseString (AreaName_F);
          IF (AreaName_F = '') THEN AreaName_F:=UpCaseString (AreaName_U);

          AreaName_F:=AddUpWithSpaces (MaxLenAreaName,AreaName_F);
          AreaName_U:=AddUpWithSpaces (MaxLenAreaName,AreaName_U);
     END;

     FieldUpdateOneField (1);
     FieldUpdateOneField (2);

     CheckAreaName:=TRUE;
END;


{---------------------------------------------------------------------------}
{ MoveMsgBase                                                               }
{                                                                           }
PROCEDURE MoveMsgBase (NewPath : STRING);
BEGIN
     IF (NOT CheckAndCreatePath (NewPath,FALSE)) THEN
        Exit;

     { not implemented yet }
     { move ENTIRE contents: lastread and admin file as well! }
     {## Finish MoveMsgBase}
END;


{---------------------------------------------------------------------------}
{ MoveJamBase                                                               }
{                                                                           }
PROCEDURE MoveJamBase (NewPath : STRING);
BEGIN
     IF (NOT CheckAndCreatePath (NewPath,TRUE)) THEN
        Exit;

     { kijk of de message base bestaat op het huidige adres }
     IF (NOT TestIfExist (CurrMsgBasePath+'.JDT')) THEN
        Exit; { old base not found there }

     { kijk of de nieuwe directory wel bestaat }
     {## Finish MoveJamBase}
END;


{---------------------------------------------------------------------------}
{ MoveSquishBase                                                            }
{                                                                           }
PROCEDURE MoveSquishBase (NewPath : STRING);
BEGIN
     IF (NOT CheckAndCreatePath (NewPath,TRUE)) THEN
        Exit;

     { not implemented yet }
     {## Finish MoveSquishBase}
END;


{---------------------------------------------------------------------------}
{ CheckAreaPath                                                             }
{                                                                           }
{ Deze routine controleert en corrigeert het ingevoerde path aan de hand    }
{ van het huidige msgbase type.                                             }
{                                                                           }
FUNCTION CheckAreaPath (BufferPtr : StringPtr) : BOOLEAN; FAR;

VAR OldLen : BYTE;

BEGIN
     OldLen:=Length (BufferPtr^);
     BufferPtr^:=CorrectPath (BufferPtr^);

     IF (AreaData.FidoMsgStyle <> FidoMsgType{jam,squish}) THEN
        IF (BufferPtr^[Length (BufferPtr^)] = '\') THEN
           Delete (BufferPtr^,Length (BufferPtr^),1);

     IF (BufferPtr^ <> CurrMsgBasePath) THEN
        CASE AreaData.FidoMsgStyle OF
             FidoMsgType:
                 MoveMsgBase (BufferPtr^);

             JamType:
                 MoveJamBase (BufferPtr^);

             SquishType:
                 MoveSquishBase (BufferPtr^);
        END; { case }

     BufferPtr^:=AddUpWithSpaces (OldLen,BufferPtr^);
END;


{--------------------------------------------------------------------------}
{ CheckNewAreaType                                                         }
{                                                                          }
{ Kijk of NET gekozen is. Zoja, gray-out de subscribers optie want netmail }
{ areas hebben geen subscribers.                                           }
{                                                                          }
PROCEDURE CheckNewAreaType; FAR;
BEGIN
     IF (AreaData.AreaType IN [Area_Netmail,Area_Local,Area_EMail]) THEN
     BEGIN
          FieldDisableField (5);   { IsInGroups }
          FieldDisableField (6);   { Subscribers }
          FieldDisableField (7);   { Allow passive }
          FieldDisableField (8);   { Passive }
          FieldDisableField (9);   { Mandatory }
          FieldDisableField (10);  { Rules }
          FieldDisableField (13);  { Add seen-by }
          FieldDisableField (14);  { Moderated }
          FieldDisableField (15);  { Dupe history }
     END ELSE
     BEGIN
          FieldEnableField (5);    { IsInGroups }
          FieldEnableField (6);    { Subscribers }
          FieldEnableField (7);    { Allow passive }
          FieldEnableField (8);    { Passive }
          FieldEnableField (9);    { Mandatory }
          FieldEnableField (10);   { Rules }
          FieldEnableField (13);   { Add seen-by }
          FieldEnableField (14);   { Moderated }
          FieldEnableField (15);   { Dupe history }
     END;

     IF (AreaData.AreaType = Area_Local) THEN
     BEGIN
          { never exporting from Local area, so no Origin fields needed }
          FieldDisableField (11);  { Origin }
          FieldDisableField (12);  { Origin AKA }
     END ELSE
     BEGIN
          FieldEnableField (11); { Origin }
          FieldEnableField (12); { Origin AKA }
     END;

     FieldUpdateOneField (5);      { IsInGroups }
     FieldUpdateOneField (6);      { Subscribers }
     FieldUpdateOneField (7);      { Allow passive }
     FieldUpdateOneField (8);      { Passive }
     FieldUpdateOneField (9);      { Mandatory }
     FieldUpdateOneField (10);     { Rules }
     FieldUpdateOneField (11);     { Origin }
     FieldUpdateOneField (12);     { Origin AKA }
     FieldUpdateOneField (13);     { Add seen-by }
     FieldUpdateOneField (14);     { Moderated }
     FieldUpdateOneField (15);     { Dupe history }
END;


{--------------------------------------------------------------------------}
{ GrayDecodePathField                                                      }
{                                                                          }
PROCEDURE GrayDecodePathField; FAR;
BEGIN
     IF AreaData.Decode THEN
        FieldEnableField (21)       { files path }
     ELSE
         FieldDisableField (21);    { files path }

     FieldUpdateOneField (21);      { files path }
END;


{--------------------------------------------------------------------------}
{ GrayPathField                                                            }
{                                                                          }
PROCEDURE GrayPathField; FAR;
BEGIN
     IF (AreaData.FidoMsgStyle <> NoneType) THEN
     BEGIN
          FieldEnableField (17);  { path }
          FieldEnableField (18);  { age }
          FieldEnableField (19);  { limit }
          FieldEnableField (20);  { decode }
          GrayDecodePathField;
     END ELSE
     BEGIN
          FieldDisableField (17); { path }
          FieldDisableField (18); { age }
          FieldDisableField (19); { limit }
          FieldDisableField (20); { decode }
          FieldDisableField (21); { file path }
     END;

     FieldUpdateOneField (17);    { path }
     FieldUpdateOneField (18);    { age }
     FieldUpdateOneField (19);    { limit }
     FieldUpdateOneField (20);    { decode }
     FieldUpdateOneField (21);    { file path }
END;


{--------------------------------------------------------------------------}
{ AreaFileMgr                                                              }
{                                                                          }
{ Deze routine wordt aangeroepen als de user op F3 drukt terwijl het pad   }
{ naar de message base ingevoerd moet worden.                              }
{                                                                          }
PROCEDURE AreaFileMgr (BufferPtr : StringPtr; CheckOnly : BOOLEAN); FAR;
BEGIN
     IF (NOT CheckOnly) THEN
        MsgBaseFileMgr (BufferPtr,AreaData.FidoMsgStyle);
END;


{--------------------------------------------------------------------------}
{ CheckDupeAgeFunc                                                         }
{                                                                          }
{ This routine checks the syntax and range of the number entered for the   }
{ dupe history.                                                            }
{                                                                          }
FUNCTION CheckDupeAgeFunc (BufferPtr : StringPtr) : BOOLEAN; FAR;

VAR Nop : ValNop;
    Age : LONGINT;

BEGIN
     CheckDupeAgeFunc:=TRUE; { never a problem, always corrected }

     Val (DeleteFrontAndBackSpaces (BufferPtr^),Age,Nop);
     IF (Nop <> 0) THEN
        Age:=2;

     IF (Age < 0) THEN
        Age:=2;

     IF (Age > 255) THEN
        Age:=255;

     AreaData.DupeAge:=Age;

     BufferPtr^:=AddUpWithSpaces (3,Byte2String (AreaData.DupeAge));
END;


{--------------------------------------------------------------------------}
{ EditFTNCharSet                                                           }
{                                                                          }
PROCEDURE EditFTNCharSet; FAR;
BEGIN
     IF (NOT CharSets_PickList (FALSE,AreaData.CharSet_FTN)) THEN
        FTNCharSetDescr:=AddUpWithSpaces (30,AreaData.CharSet_FTN);
END;


{--------------------------------------------------------------------------}
{ EditRFCCharSet                                                           }
{                                                                          }
PROCEDURE EditRFCCharSet; FAR;
BEGIN
     IF (NOT CharSets_PickList (TRUE,AreaData.CharSet_RFC)) THEN
        RFCCharSetDescr:=AddUpWithSpaces (30,AreaData.CharSet_RFC);
END;


{--------------------------------------------------------------------------}
{ DrawAreaBaseRecordScreen                                                 }
{                                                                          }
{ Deze routine tekent het scherm waarin de Area Data komt te staan en      }
{ gewijzigd kan worden. De Field referentie worden aan de globaal gedefi-  }
{ nieerde AreaData variabele gelegd. Alleen de AreaData.AreaType variabele }
{ moet al gevuld zijn om te bepalen of het een UseNet of FIDO bord is, of  }
{ in de toekomst een ander.                                                }
{                                                                          }
PROCEDURE DrawAreaBaseRecordScreen;

VAR Xb,
    Xb2,
    Yb,
    Xl,
    Yl,
    Sl,
    FieldY : XYType;

BEGIN
     IF (Video.Rows > 25) THEN
     BEGIN
          { keep window }
          Xb:=1;
          Yb:=5;
          Xl:=78;
          Yl:=25;
          Xb2:=Xb+16;
          Sl:=61;

          WindowPush (Xb,Yb,Xl,Yl);
          BoxDraw (Double,Xb,Yb,Xl,Yl);
     END ELSE
     BEGIN
          { fit screen, no border }
          Xb:=1;
          Yb:=2;
          Xl:=80;
          Yl:=23;
          Xb2:=Xb+16;
          Sl:=63;

          WindowPush (Xb,Yb,Xl,Yl);
          BoxDrawNS (Double,Xb,Yb,Xl,Yl);
     END;

     FieldInit;

     FieldY:=Yb+1;

     WriteXY (Xb+2,FieldY,'FTN name');
     FieldAutoDefineCheckOne (Xb2,FieldY,
                              @AreaData.AreaName_F,
                              RepChar (MaxLenAreaName,'>'),
                              CheckAreaName);
     FieldSetHelp (0,htr_AreaEdit_AreaName);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'RFC name');
     FieldAutoDefineCheckOne (Xb2,FieldY,
                              @AreaData.AreaName_U,
                              RepChar (MaxLenAreaName,'<'),
                              CheckAreaName);
     FieldSetHelp (0,htr_AreaEdit_AreaName);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Comment');
     FieldAutoDefineOne (Xb2,FieldY,@AreaData.Comment,RepChar (MaxLenComment,'$'));
     FieldSetHelp (0,htr_AreaEdit_Comment);

     Inc (FieldY);
     WriteXY(Xb+2,FieldY,'Type');
     FieldAutoDefineTogglesCall (Xb2,FieldY,AreaData.AreaType,'echo|net|local|e-mail',0,CheckNewAreaType);
     FieldSetHelp (0,htr_AreaEdit_AreaType);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'In groups');
     FieldAutoDefineList (Xb2,FieldY,@GroupListDesc,EditAreaGroupsList);
     FieldSetHelp (0,htr_AreaEdit_InGroups);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Subscribers');
     FieldAutoDefineList (Xb2,FieldY,@DotDotDot,EditAreaSubscrList);
     FieldSetHelp (0,htr_AreaEdit_Subscribers);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Allow Passive');
     FieldAutoDefineToggles (Xb2,FieldY,AreaData.AllowPassive,'no|yes',0);
     FieldSetHelp (0,htr_AreaEdit_AllowPassive);

     IF (Video.Rows > 25) THEN
     BEGIN
          Inc (FieldY);
          WriteXY (Xb+2,FieldY,'Passive');
          FieldAutoDefineToggles (Xb2,FieldY,AreaData.Passive,'no|yes',0);
          FieldSetHelp (0,htr_AreaEdit_Passive);
     END ELSE
     BEGIN
          { put the field after the "Allow Passive" field }
          WriteXY (Xb+25,FieldY,'Passive');
          FieldAutoDefineToggles (Xb+33,FieldY,AreaData.Passive,'no|yes',0);
          FieldSetHelp (0,htr_AreaEdit_Passive);
     END;

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Mandatory');
     FieldAutoDefineToggles (Xb2,FieldY,AreaData.Mandatory,'no|yes',0);
     FieldSetHelp (0,htr_AreaEdit_Mandatory);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Rules file');
     FieldAutoDefineFileMgr (Xb2,FieldY,Sl,@AreaData.RulesFile,AnyFileMgr,FALSE);
     FieldSetHelp (0,htr_AreaEdit_RulesFile);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Origin');
     FieldAutoDefineList (Xb2,FieldY,@OriginDesc,EditAreaOrigin);
     FieldSetHelp (0,htr_AreaEdit_Origin);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Origin AKA');
     FieldAutoDefineList (Xb2,FieldY,@OriginAkaStr,EditAreaOriginAka);
     FieldSetHelp (0,htr_AreaEdit_OriginAKA);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Add SEEN-BY');
     FieldAutoDefineList (Xb2,FieldY,@DotDotDot,EditAreaAddSeenByList);
     FieldSetHelp (0,htr_AreaEdit_AddSEENBY);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Moderator');
     FieldAutoDefineList (Xb2,FieldY,@ModeratorDesc,EditAreaModeration);
     FieldSetHelp (0,htr_AreaEdit_Moderator);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Dupe history      (weeks)');
     FieldAutoDefineCheckOne (Xb2,FieldY,@DupeHistoryStr,'%%%',CheckDupeAgeFunc);
     FieldSetHelp (0,htr_AreaEdit_DupeHistory);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Msg base type');
     FieldAutoDefineTogglesCall (Xb2,FieldY,AreaData.FidoMsgStyle,'pass-through|msg|squish|jam',0,GrayPathField);
     FieldSetHelp (0,htr_AreaEdit_MsgBaseType);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Msg base path');
     FieldAutoDefineFileMgr (Xb2,FieldY,Sl,@AreaData.FidoMsgPath,AreaFileMgr,FALSE);
     FieldSetHelp (0,htr_AreaEdit_MsgBasePath);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Message age');
     FieldAutoDefineOne (Xb2,FieldY,@FidoMsgAgeStr,'%%%%%');
     FieldSetHelp (0,htr_AreaEdit_MsgBaseAge);

     IF (Video.Rows > 25) THEN
     BEGIN
          Inc (FieldY);
          WriteXY (Xb+2,FieldY,'Message limit');
          FieldAutoDefineOne (Xb2,FieldY,@FidoMsgLimitStr,'%%%%%');
          FieldSetHelp (0,htr_AreaEdit_MsgBaseLimit);
     END ELSE
     BEGIN
          { put this field behind the "Message Age" field }
          WriteXY (Xb+25,FieldY,'Message limit');
          FieldAutoDefineOne (Xb+33,FieldY,@FidoMsgLimitStr,'%%%%%');
          FieldSetHelp (0,htr_AreaEdit_MsgBaseLimit);
     END;

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Decode files');
     FieldAutoDefineTogglesCall (Xb2,FieldY,AreaData.Decode,'no|on import',0,GrayDecodePathField);
     FieldSetHelp (0,htr_AreaEdit_DecodeFiles);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Files path');
     FieldAutoDefineFileMgr (Xb2,FieldY,Sl,@AreaData.DecodePath,PathFileMgr,FALSE);
     FieldSetHelp (0,htr_AreaEdit_FilesPath);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'FTN charset');
     FieldAutoDefineList (Xb2,FieldY,@FTNCharSetDescr,EditFTNCharSet);
     FieldSetHelp (0,htr_AreaEdit_Charsets);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'RFC charset');
     FieldAutoDefineList (Xb2,FieldY,@RFCCharSetDescr,EditRFCCharSet);
     FieldSetHelp (0,htr_AreaEdit_Charsets);
END;


{--------------------------------------------------------------------------}
{ UnfixAreaBaseRecord                                                      }
{                                                                          }
{ Verwijderd onnodige spaties uit een areabase record voor het weg         }
{ schrijven. Onderdeel van het 'DeleteBackSpaces' project.                 }
{                                                                          }
PROCEDURE UnfixAreaBaseRecord;
BEGIN
     WITH AreaData DO
     BEGIN
          AreaName_F:=DeleteBackSpaces (AreaName_F);
          AreaName_U:=DeleteBackSpaces (AreaName_U);
          Comment:=DeleteBackSpaces (Comment);
          Origin:=DeleteBackSpaces (Origin);
          FidoMsgPath:=DeleteBackSpaces (FidoMsgPath);
          Moderator:=DeleteBackSpaces (Moderator);
          DecodePath:=DeleteFrontAndBackSpaces (DecodePath);
          RulesFile:=DeleteFrontAndBackSpaces (RulesFile);
          CharSet_FTN:=DeleteFrontAndBackSpaces (CharSet_FTN);
          CharSet_RFC:=DeleteFrontAndBackSpaces (CharSet_RFC);
     END; { with }
END;


{--------------------------------------------------------------------------}
{ CheckAreaBaseRecord                                                      }
{                                                                          }
{ Controleerd (& Converteerd) een areabase record alvorens het naar disk   }
{ te schrijven.                                                            }
{                                                                          }
PROCEDURE CheckAreaBaseRecord;

VAR Nop : ValNop;

BEGIN
     { Converteer FidoMsgAgeStr naar FidoMsgAge }
     Val (DeleteBackSpaces (FidoMsgAgeStr),AreaData.FidoMsgAge,Nop);
     IF (Nop <> 0) OR (AreaData.FidoMsgAge < 0) THEN
        AreaData.FidoMsgAge:=Config.DefDaysToKeep_F;

     { Converteer FidoMsgLimitStr naar FidoMsgLimit }
     Val (DeleteBackSpaces (FidoMsgLimitStr),AreaData.FidoMsgLimit,Nop);
     IF (Nop <> 0) OR (AreaData.FidoMsgLimit < 0) THEN
        AreaData.FidoMsgLimit:=Config.DefNumbToKeep_F;

     UnfixAreaBaseRecord;
END;


{--------------------------------------------------------------------------}
{ EditAreaBaseRecord                                                       }
{                                                                          }
{ Deze routine geeft TRUE terug als de Area Name van het record is         }
{ aangepast en de select lijst dus geupdate moet worden.                   }
{                                                                          }
FUNCTION EditAreaBaseRecord (RecNr : AreaBaseRecordNrType) : BOOLEAN;

TYPE Cmp = ARRAY[1..SizeOf (AreaBaseRecord)] OF BYTE;

VAR Quit   : BOOLEAN;
    Lp     : WORD;
    Loaded : BOOLEAN;

BEGIN
     EditAreaBaseRecord:=FALSE;

     ReadAreaBaseRecord (RecNr,AreaData);
     AreaRecNr:=RecNr;

     { lower case here (fix does it as well) to prevent mismatch }
     { when checking to save it.                                 }
     AreaData.AreaName_F:=UpCaseString (AreaData.AreaName_F);
     AreaData.AreaName_U:=LoCaseString (AreaData.AreaName_U);
     OldAreaData:=AreaData;

     CurrMsgBasePath:=AreaData.FidoMsgPath;

     FixAreaDataRecord (AreaData);
     DrawAreaBaseRecordScreen;

     IF (AreaData.AreaType = Area_Echo) THEN
        FieldSetFirst (6); { subscribers }

     Quit:=FALSE;
     WHILE NOT Quit DO
     BEGIN
          FixAreaDataRecord (AreaData);

          { graying }
          CheckNewAreaType;
          GrayDecodePathField;
          GrayPathField;
          GrayOriginField;

          FieldEdit;

          Quit:=TRUE;
          CheckAreaBaseRecord;

          Loaded:=FALSE;

          { Als de ingevoerde naam anders is dan de naam waarmee we }
          { begonnen controleer dan of die nieuwe naam al bestaat.  }
          IF (OldAreaData.AreaName_F <> AreaData.AreaName_F) THEN
          BEGIN
               IF (NOT Loaded) THEN
               BEGIN
                    Message ('Checking...');
                    ReadAreaBaseIndexTable;
                    WindowPop;
                    Loaded:=TRUE;
               END;

               IF (GetAreaBaseRecordNrByAreaName_F (DeleteBackSpaces (AreaData.AreaName_F)) <> NilRecordNr) THEN
               BEGIN
                    Error ('FTN areaname already exists!');
                    Quit:=FALSE;
               END;
          END;

          IF (OldAreaData.AreaName_U <> AreaData.AreaName_U) THEN
          BEGIN
               IF (NOT Loaded) THEN
               BEGIN
                    Message ('Checking...');
                    ReadAreaBaseIndexTable;
                    WindowPop;
                    Loaded:=TRUE;
               END;

               IF (GetAreaBaseRecordNrByAreaName_U (DeleteBackSpaces (AreaData.AreaName_U)) <> NilRecordNr) THEN
               BEGIN
                    Error ('RFC areaname already exists!');
                    Quit:=FALSE;
               END;
          END;

          IF Loaded THEN
             JunkAreaBaseIndexTable;

          IF (DeleteBackSpaces (AreaData.AreaName_F) = '') THEN
          BEGIN
               Error ('No Area Name defined !');
               Quit:=FALSE;
          END;

          IF Quit AND TestGroupListIsEmpty (AreaData.IsInGroups) THEN
          BEGIN
               IF (AreaData.AreaType <> Area_Echo) THEN
               BEGIN
                    AddGroupToGroupList (AreaData.IsInGroups,MaxGroups); { Z3 }
                    Error ('Area has been put in group Z3');
               END ELSE
                   Error ('Area is in NO groups!');

               Quit:=FALSE;
          END;

          IF (AreaData.AreaType = Area_EMail) AND
             (AreaData.FidoMsgStyle = FidoMsgType) THEN
          BEGIN
               Error ('*.MSG not possible with E-Mail area!');
               Quit:=FALSE;
          END;

          IF Quit THEN
             WriteAreaBaseRecord (RecNr,AreaData);

          { test whether we have to update the list }
          IF (OldAreaData.AreaName_F <> AreaData.AreaName_F) OR
             (OldAreaData.AreaName_U <> AreaData.AreaName_U) OR
             (NOT TestGroupListSame (OldAreaData.IsInGroups,AreaData.IsInGroups)) THEN
           BEGIN
                EditAreaBaseRecord:=TRUE;
           END;

     END; { while }

     WindowPop; { AreaBaseRecordScreen }
END;


{--------------------------------------------------------------------------}
{ CreateNewAreaBaseRecord                                                  }
{                                                                          }
{ Met deze routine kan een nieuw record in de Area Database aangemaakt     }
{ worden. Er wordt een Area Data scherm opgezet waarin alle velden leeg    }
{ zijn gemaakt en het invullen kan beginnen. Door op Escape te drukken     }
{ wordt de invoer afgesloten en wordt gevraagd of het record aangemaakt    }
{ mag worden.                                                              }
{ Er wordt TRUE terug gegeven als de Area Database is uitgebreid met een   }
{ nieuw record en er dus wat aan de select lijst gedaan moet worden.       }
{                                                                          }
{ Routine aangepast, zodat eventuele al aangesloten gebruikers ook         }
{ afgesloten worden.                                                       }
{                                                                          }
FUNCTION CreateNewAreaBaseRecord (GroupsFilter : GroupFlagType) : BOOLEAN;

VAR Quit     : BOOLEAN;
    GroupLp  : 1..MaxGroups;
    GroupRec : GroupDescRecord;

BEGIN
     CreateNewAreaBaseRecord:=FALSE;                 { nog niets aangmaakt }
     EmptyAreaDataRecord (AreaData);

     { RvdW 03-04-93 Volgende twee regels ingevoegd om fouten bij het }
     {               subscriben van users te voorkomen.               }
     AreaRecNr:=AreaBaseRecCount+1; { niet wijzigen, dan gaat de select list op zijn bek ivm geen rebuild meer }
     AreaData.IsInGroups:=GroupsFilter;
     AreaData.Deleted:=TRUE;

     { origin AKA invullen }
     FOR GroupLp:=1 TO MaxGroups DO
         IF TestIfInGroup (GroupsFilter,GroupLp) THEN
         BEGIN
              ReadGroupDescRecord (GroupLp,GroupRec);
              AreaData.OriginAka:=GroupRec.OriginAka;
              SetSingleSeenByBit (AreaData.AddSeenByAkas,AreaData.OriginAka);
              Break;
         END;

     FixAreaDataRecord (AreaData);
     WriteAreaBaseRecord (AreaRecNr,AreaData);

     { scherm opzetten }
     DrawAreaBaseRecordScreen;
     PushKeysLine;
     WriteKeysLine (' ^Esc end edit  ^'#24#25' select field  ^Enter edit field');

     Quit:=FALSE;
     REPEAT
           FixAreaDataRecord (AreaData);
                              { RWI 201094: toegevoegd, anders namen zonder }
                              {             addspaces bij tweede doorgang   }
                              {             ivm invoer fout (areaname leeg) }

           CheckNewAreaType;
           GrayDecodePathField;
           GrayPathField;

           FieldEdit;

           CheckAreaBaseRecord;

           CASE Key OF
                kF10,
                kEsc :
                    BEGIN
                          MenuDefine (6,15,'Save changes?');
                          MenuAddItem ('Yes');
                          MenuAddItem ('No');
                          MenuShow;

                          CASE MenuSelect OF
                               mOpt01 :
                                   BEGIN
                                        Quit:=TRUE;

                                        IF (DeleteBackSpaces (AreaData.AreaName_F) = '') THEN
                                        BEGIN
                                             Error ('No Area Name defined!');
                                             FieldSetFirst (1);
                                             Quit:=FALSE;
                                        END;

                                        { impossible.. }
                                        IF TestGroupListIsEmpty (AreaData.IsInGroups) AND Quit THEN
                                        BEGIN
                                             Error ('Area is in NO groups!');
                                             Quit:=FALSE;
                                        END;

                                        IF (AreaData.AreaType = Area_EMail) AND
                                           (AreaData.FidoMsgStyle = FidoMsgType) THEN
                                        BEGIN
                                             Error ('*.MSG not possible with E-Mail area!');
                                             Quit:=FALSE;
                                        END;

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

                                        IF Quit THEN
                                        BEGIN
                                             ReadAreaBaseIndexTable;

                       IF (GetAreaBaseRecordNrByAreaName_F (DeleteBackSpaces (AreaData.AreaName_F)) <> NILRecordNr) THEN
                                             BEGIN
                                                  Error ('FTN name already exists!');
                                                  FieldSetFirst (1);
                                                  Quit:=FALSE;
                                             END ELSE
                       IF (GetAreaBaseRecordNrByAreaName_U (DeleteBackSpaces (AreaData.AreaName_U)) <> NILRecordNr) THEN
                                                 BEGIN
                                                      Error ('RFC name already exists!');
                                                      FieldSetFirst (2);
                                                      Quit:=FALSE;
                                                 END;

                                             JunkAreaBaseIndexTable;
                                        END;

                                        IF Quit THEN
                                        BEGIN
                                             AreaData.Deleted:=FALSE;
                                             WriteAreaBaseRecord (AreaRecNr,AreaData);
                                             CreateNewAreaBaseRecord:=TRUE; { database is aangepast }
                                        END;

                                        WindowPop;
                                   END; { mOpt01 }

                               mOpt02 :
                                   BEGIN
                                        Quit:=TRUE;
                                        AreaData.Deleted:=TRUE;
                                        DeleteAreaBaseRecord (AreaRecNr,FALSE,FALSE);
                                   END;
                          END; { case }

                          MenuErase;
                     END; { kEsc }
           END; { case }
     UNTIL Quit;

     PopKeysLine;
     WindowPop; { AreaBaseRecordScreen }
END;


{--------------------------------------------------------------------------}
{ DeleteAreaBaseRecord                                                     }
{                                                                          }
{ Met deze routine kan een record uit de Area Base verwijderd worden. Er   }
{ wordt hier niet om een bevesting gevraagd, dat moet door de aanroeper    }
{ gedaan zijn ivm meerdere aanroepen door tags.                            }
{                                                                          }
PROCEDURE DeleteAreaBaseRecord (RecNr : AreaBaseRecordNrType; KillBase,RapidDelete : BOOLEAN);

VAR AreaData : AreaBaseRecord;
    UserData : UserBaseRecord;
    Search   : SubscrSearchRecord;
    ZoekRec  : SearchRec;
    KillFile : FILE;
    IORes    : BYTE;

BEGIN
     ReadAreaBaseRecord (RecNr,AreaData);

     IF (NOT RapidDelete) THEN
     BEGIN
          GetFirstUserSubscribedToThisArea (AreaData.UserList,Search);

          WHILE (Search.Found) DO
          BEGIN
               { RWI 950812: niet meer nodig. PackBase ruimte wel op }
               { RemoveUserFromAreaSubscrList (AreaData,Search.UserBaseRecordNr);}

               ReadUserBaseRecord (Search.UserBaseRecordNr,UserData);
               RemoveAreaFromUserSubscrToList (UserData,RecNr);

               { RWI 950812: Userbase record hoeft niet weggeschreven te worden! }
               { WriteUserBaseRecord (Search.UserBaseRecordNr,UserData);}

               GetNextUserSubscribedToThisArea (Search);
          END; { while }
     END; { not rapid delete }

     { RWI 950310: test op KillBase toegevoegd }
     IF KillBase THEN
     BEGIN
          { Aangezien een record nog niet weggeschreven hoeft te zijn }
          AreaData.FidoMsgPath:=DeleteBackSpaces (AreaData.FidoMsgPath);

          CASE AreaData.FidoMsgStyle OF
               FidoMsgType :
                   BEGIN
                        FindFirst (AreaData.FidoMsgPath+'*.MSG',saJustFiles,ZoekRec);
                        WHILE (DosError = 0) DO
                        BEGIN
                             Assign (KillFile,AreaData.FidoMsgPath+ZoekRec.Name);
                             {$I-} Erase (KillFile); {$I+} IORes:=IOResult;
                             FindNext (ZoekRec);
                        END;
                        FindClose (ZoekRec);

                        Assign (KillFile,AreaData.FidoMsgPath+'LASTREAD');
                        {$I-} Erase (KillFile); {$I+}
                        IORes:=IOResult; { Negeer de resultaten }

                        Assign (KillFile,AreaData.FidoMsgPath+'MSGINDEX.WG');
                        {$I-} Erase (KillFile); {$I+}
                        IORes:=IOResult; { Negeer de resultaten }

                        { probeer de directory ook weg te halen }
                        Dec (AreaData.FidoMsgPath[0]); { delete backslash }
                        {$I-} RmDir (AreaData.FidoMsgPath); {$I+}
                        IORes:=IOResult; { ignore }
                   END;

               SquishType :
                   BEGIN
                        { Probeer alle Squish files van een area te verwijderen }
                        {$I-}
                        Assign (KillFile,AreaData.FidoMsgPath+'.SQL');
                        Erase (KillFile);
                        Assign (KillFile,AreaData.FidoMsgPath+'.SQD');
                        Erase (KillFile);
                        Assign (KillFile,AreaData.FidoMsgPath+'.SQI');
                        Erase (KillFile);
                        IORes:=IOResult;
                        {$I+}
                   END;

               JamType :
                   BEGIN
                        { Probeer alle JAM files van een area te verwijderen }
                        {$I-}
                        Assign (KillFile,AreaData.FidoMsgPath+'.JLR');
                        Erase (KillFile);
                        Assign (KillFile,AreaData.FidoMsgPath+'.JDT');
                        Erase (KillFile);
                        Assign (KillFile,AreaData.FidoMsgPath+'.JDX');
                        Erase (KillFile);
                        Assign (KillFile,AreaData.FidoMsgPath+'.JHR');
                        Erase (KillFile);
                        IORes:=IOResult;
                        {$I+}
                   END;
          END;
     END;

     { nu is er niemand meer op aangesloten }
     AreaData.UserList:=NILRecordNr;

     { en nu maken we em dood }
     AreaData.Deleted:=TRUE;

     WriteAreaBaseRecord (RecNr,AreaData);
END;


{--------------------------------------------------------------------------}
{ DeleteBaseFiles                                                          }
{                                                                          }
{ Vraagt of de gebruiker ook de lokale bestanden wil verwijderen als die   }
{ bestaan.                                                                 }
{                                                                          }
FUNCTION DeleteBaseFiles : BOOLEAN;

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

BEGIN
     MenuDefine (25,7,'Delete Message Base files as well?');
     MenuAddItem ('Yes');
     MenuAddItem ('No');
     MenuSetHelp (htr_AreaEdit_DeleteMsgBaseFilesAsWell);
     MenuShow;

     REPEAT
           MenuSelect;
     UNTIL (Key IN [mOpt01,mOpt02]);

     DeleteBaseFiles:=(Key = mOpt01);

     MenuErase;
END;


{==========================================================================}
{                         GLOBAL AREA CHANGES                              }
{==========================================================================}


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeOriginAKA                                                 }
{                                                                          }
{ Verandert de origin aka van een geselecteerde group areas.               }
{                                                                          }
PROCEDURE AreaGlob_ChangeOriginAKA;

VAR AkaLp  : 1..MaxAKAs;
    Keuze  : WORD;
    AreaLp : WORD;
    Quit   : BOOLEAN;

BEGIN
     ListDefine (3,3,39,Video.Rows-4,Default,
                 'Select a new Origin AKA',
                 htr_AreaGlobEdit_NewOriginAKA);

     ListSetConvertRoutine (FidoAkaListConvertFunc);

     FOR AkaLp:=1 TO MaxAKAs DO
         IF NOT FidoCompare (Config.NodeNrs[AkaLp],NullAdres) THEN { RWI 970113 }
            ListAddItem (Fido2Str (Config.NodeNrs[AkaLp]),AkaLp,Convert);

     IF (ListItemCount = 0) THEN
        ListAddItem (Fido2Str (Config.NodeNrs[AkaLp]),1,Convert);

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

           CASE Key OF
                kRet : BEGIN
                            ListErase;

                            MenuDefine (30,7,'Swap AKAs in SEEN-BY list?');
                            MenuAddItem ('Yes');
                            MenuAddItem ('No');
                            MenuAddItem ('Back to the area list');
                            MenuAddItem ('More information (F1)');
                            MenuSetHelp (htr_AreaGlobEdit_NewOriginAKA_ChangeSeenByList);
                            MenuShow;

                            REPEAT
                                  IF (MenuSelect = mOpt04) THEN
                                     RequestHelp (4209);

                            UNTIL (Key IN [kEsc,mOpt01..mOpt03]);

                            MenuErase;

                            IF (Key IN [kEsc,mOpt03]) THEN
                               Exit;

                            Message ('Updating area records with new Origin AKA');

                            { Doorloop alle areas die geselecteerd waren }
                            { in de VORIGE select lijst.                 }
                            FOR AreaLp:=1 TO ListTagCount DO
                            BEGIN
                                 ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLp),AreaData);

                                 { verwijder oude AKA }
                                 IF (Key = mOpt01) THEN
                                    ResetSeenByBit (AreaData.AddSeenByAkas,AreaData.OriginAKA);

                                 AreaData.OriginAKA:=Keuze;

                                 { voeg nieuwe AKA toe }
                                 SetSeenByBit (AreaData.AddSeenByAkas,AreaData.OriginAKA);

                                 WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLp),AreaData);
                            END; { for }

                            WindowPop; { message }
                            Quit:=TRUE;
                       END;

                kEsc : BEGIN
                            ListErase;
                            Quit:=TRUE;
                       END;
           END; { case }
     UNTIL Quit;
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeSeenBys                                                   }
{                                                                          }
{ Verandert de "add SEEN_BYs" van een geselecteerde group areas.           }
{                                                                          }
PROCEDURE AreaGlob_ChangeSeenBys;

VAR AreaLp : WORD;
    NewSB  : ARRAY[1..13] OF BYTE;

BEGIN
     EditAreaAddSeenByList;

     MenuDefine (15,255,'Are you sure?');
     MenuAddItem ('Yes, replace SEEN-BY list for all selected areas');
     MenuAddItem ('No');
     MenuShow;
     MenuSelect;
     MenuErase;

     IF (Key <> mOpt01) THEN
        Exit;

     Message ('Updating area records with new SEEN-BY list');

     Move (AreaData.AddSeenByAKAs,NewSB,13);

     { Doorloop alle areas die geselecteerd waren }
     { in de VORIGE select lijst.                 }
     FOR AreaLp:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLp),AreaData);
          Move (NewSB,AreaData.AddSeenByAKAs,13);
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLp),AreaData);
     END; { for }

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeCustomOrigin                                              }
{                                                                          }
{ Vraag om een nieuwe custom voor een group areas.                         }
{                                                                          }
PROCEDURE AreaGlob_ChangeCustomOrigin;

CONST Xb = 10;
      Yb = 10;
      Xl = MaxlenOrigin+4;
      Yl = 6;

VAR NewOrigin : STRING[MaxLenOrigin];
    AreaLoop  : LONGINT;

BEGIN
     NewOrigin:=RepChar (MaxLenOrigin,' ');

     { Bouw een menu veldje , en vraag om een nieuwe custom origin line }
     FieldPushAll;

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

     WriteXY (Xb+2,Yb+1,'Enter a new custom origin line for the selected areas:');

     FieldInit;
     FieldDefineOne (1,Xb+2,Yb+3,MaxLenOrigin{=60},1,1,@NewOrigin,RepChar (MaxLenOrigin,'$'));
     FieldSetHelp (1,htr_AreaGlobEdit_ChangeCustomOrigin);
     FieldEditDirect;

     WindowPop;
     FieldPopAll;

     IF (Key = kEsc) THEN
        Exit;

     NewOrigin:=DeleteBackSpaces (NewOrigin);

     Message ('Updating Area Records with new custom origin');

     { doorloop alle areas die geselecteerd waren }
     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
          AreaData.Origin:=NewOrigin;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
     END; { for }

     WindowPop;
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeDefaultOrigin                                             }
{                                                                          }
{ Veranderd de default origin van een area, gekozen kan worden uit de      }
{ 2 origins in de configuratie, of een custom origin.                      }
{                                                                          }
PROCEDURE AreaGlob_ChangeDefaultOrigin;

VAR OriginNr : BYTE;
    AreaLoop : WORD;

BEGIN
     MenuDefine (3,3,'Select a new origin line for the selected areas');
     MenuAddItem ('Custom');
     MenuAddItem (DeleteBackSpaces (Config.Origins[1]));
     MenuAddItem (DeleteBackSpaces (Config.Origins[2]));
     MenuSetHelp (htr_AreaGlobEdit_ChangeDefaultOrigin);
     MenuShow;
     MenuSelect;
     MenuErase;

     CASE Key OF
          kEsc : Exit;

          mOpt01 : OriginNr:=0;
          mOpt02 : OriginNr:=1;
          mOpt03 : OriginNr:=2;
     END; { case }

     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
          AreaData.OriginNr:=OriginNr;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
     END; { for }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeBaseAge                                                        }
{                                                                          }
{ Verandert de berichten expire datum van de geselecteerde bases.          }
{                                                                          }
PROCEDURE AreaGlob_ChangeBaseAge;

CONST Xb = 15;
      Yb = 10;
      Xl = 55;
      Yl = 3;

VAR AreaLoop   : WORD;
    AreaExpire : STRING[6];
    Nop        : ValNop;
    Value      : INTEGER;

BEGIN
     AreaExpire:=AddUpWithSpaces (5,Word2String (Config.DefDaysToKeep_F));

     { bouw een menu veldje en vraag om een nieuwe custom origin line }
     FieldPushAll;

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

     WriteXY (Xb+2,Yb+1,'Enter an expire age for the selected areas:');

     FieldInit;
     FieldDefineOne (1,Xb+47,Yb+1,5,1,1,@AreaExpire,'%%%%%%');
     FieldSetHelp (1,htr_AreaGlobEdit_MessageAge);
     FieldEditDirect;

     WindowPop;
     FieldPopAll;

     { converteer FidoMsgAgeStr naar FidoMsgAge }
     Val (DeleteBackSpaces (AreaExpire),Value,Nop);

     IF (Nop <> 0) OR (Value < 0) THEN
     BEGIN
          Error ('Invalid entry !');
          Exit;
     END;

     IF (Key = kEsc) THEN
        Exit;

     Message ('Updating Area Records with new expire days');

     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
          AreaData.FidoMsgAge:=Value;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
     END; { for }

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeBaseLimits                                                }
{                                                                          }
{ Verandert het maximum aantal berichten dat in een area blijft staan.     }
{                                                                          }
PROCEDURE AreaGlob_ChangeBaseLimits;

CONST Xb = 10;
      Yb = 10;
      Xl = 63;
      Yl = 3;

VAR AreaLoop   : LONGINT;
    AreaExpire : STRING[6];
    Nop        : ValNop;
    Value      : INTEGER;

BEGIN
     AreaExpire:=AddUpWithSpaces (5,Word2String (Config.DefNumbToKeep_F));

     { Bouw een menu veldje , en vraag om een nieuwe custom origin line }
     FieldPushAll;

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

     WriteXY (Xb+2,Yb+1,'Enter maximum message number for the selected areas :');

     FieldInit;
     FieldDefineOne (1,Xb+56,Yb+1,5,1,1,@AreaExpire,'%%%%%%');
     FieldSetHelp (1,htr_AreaGlobEdit_MessageLimit);
     FieldEditDirect;

     WindowPop;
     FieldPopAll;

     { Converteer FidoMsgAgeStr naar FidoMsgAge }
     Val (DeleteBackSpaces (AreaExpire),Value,Nop);

     IF (Nop <> 0) OR (Value < 0) THEN
     BEGIN
          Error('Invalid entry !');
          Exit;
     END;

     IF (Key = kEsc) THEN
        Exit;

     Message ('Updating Area Records with new maximum messages');

     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
          AreaData.FidoMsgLimit:=Value;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
     END; { for }

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeBaseType                                                  }
{                                                                          }
{ Veranderd het base type van een groep area's.                            }
{ RWI 151094: Bij veranderen naar None kunnen op verzoek de msgbase files  }
{             verwijderd worden.                                           }
{                                                                          }
PROCEDURE AreaGlob_ChangeBaseType;

     {---------------------------------------------------------------------}
     { TryDelete                                                           }
     {                                                                     }
     { Deze routine probeert de opgegeven msgbase file te verwijderen.     }
     {                                                                     }
     PROCEDURE TryDelete (Name : STRING);

     VAR DelFile : FILE;
         IORes   : BYTE;

     BEGIN
          Assign (DelFile,Name);
          {$I-} Erase (DelFile); {$I+} IORes:=IOResult;
     END;

VAR NewStyle : FidoMsgStyleType;
    AreaLoop : LONGINT;
    DelFiles : BOOLEAN;

BEGIN
     MenuDefine (3,3,'Select a new message base type for the selected areas');
     MenuAddItem ('Pass-through');
     MenuAddItem ('*.MSG');
     MenuAddItem ('Squish');
     MenuAddItem ('Jam');
     MenuSetHelp (htr_AreaGlobEdit_ChangeMsgBaseType);
     MenuShow;

     DelFiles:=FALSE;

     CASE MenuSelect OF
          kEsc : BEGIN
                      MenuErase;
                      Exit;
                 END;

          mOpt01 : BEGIN
                        NewStyle:=NoneType;
                        DelFiles:=DeleteBaseFiles;
                   END;

          mOpt02 : NewStyle:=FidoMsgType;
          mOpt03 : NewStyle:=SquishType;
          mOpt04 : NewStyle:=JamType;
     END; { case }

     MenuErase;
     Message ('Updating Area Records with new area type');

     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);

          IF DelFiles THEN
          BEGIN
               { probeer de msgbase files weg te halen van de HD }

               { mogelijke files:
                 JAM: (4) .JHR .JDT .JDX .JLR
                 Squish: (4) .SQD .SQB .SQM .SQI
               }
               CASE AreaData.FidoMsgStyle OF
                    JAMType :
                        BEGIN
                             TryDelete (AreaData.FidoMsgPath+'.JHR');
                             TryDelete (AreaData.FidoMsgPath+'.JDT');
                             TryDelete (AreaData.FidoMsgPath+'.JDX');
                             TryDelete (AreaData.FidoMsgPath+'.JLR');
                        END;

                    SquishType :
                        BEGIN
                             TryDelete (AreaData.FidoMsgPath+'.SQD');
                             TryDelete (AreaData.FidoMsgPath+'.SQB');
                             TryDelete (AreaData.FidoMsgPath+'.SQM');
                             TryDelete (AreaData.FidoMsgPath+'.SQI');
                        END;

               END; { case }
          END; { delfiles }

          AreaData.FidoMsgStyle:=NewStyle;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
     END;

     WindowPop;
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeDirectory                                                 }
{                                                                          }
{ Veranderd de directoryies van een group areas. Door te kijken of het     }
{ begin van het areapath overeenkomt, probeert deze de directory te        }
{ veranderen.                                                              }
{                                                                          }
PROCEDURE AreaGlob_ChangeDirectory;

CONST Xb = 15;
      Yb = 10;
      Xl = 54;
      Yl = 6;

VAR AreaLoop : LONGINT;

    SearchPath,
    ReplacePath : FilePathStr;

    Nop,
    Value  : INTEGER;

BEGIN
     FieldPushAll;

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

     SearchPath:=RepChar (MaxLenPath,' ');
     ReplacePath:=RepChar (MaxLenPath,' ');

     WriteXY (Xb+2,Yb+1,'Enter the directory to search for   : ');
     WriteXY (Xb+2,Yb+3,'Enter the directory to replace with : ');

     FieldInit;

     FieldDefineLongOne (1,Xb+2,Yb+2,MaxLenPath,50,2,2,@SearchPath,RepChar (MaxLenPath,'$'));
     FieldDefineLongOne (2,Xb+2,Yb+4,MaxLenPath,50,1,1,@ReplacePath,RepChar (MaxLenPath,'$'));

     FieldSetHelp (1,htr_AreaGlobEdit_ChangePath);
     FieldSetHelp (2,htr_AreaGlobEdit_ChangePath);

     FieldEdit;

     WindowPop; { edit window }
     FieldPopAll;

     SearchPath:=UpCaseString (DeleteBackspaces (SearchPath));
     ReplacePath:=UpCaseString (DeleteBackspaces (ReplacePath));

     IF (SearchPath = '') OR (ReplacePath = '') THEN
     BEGIN
          Error ('You cannot search and replace nothing!');
          Exit;
     END;

     Message ('Updating Area Records with new area path');

     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);

          IF (Copy (AreaData.FidoMsgPath,1,Length (SearchPath)) = SearchPath) THEN
          BEGIN
               Delete (AreaData.FidoMsgPath,1,Length (SearchPath));
               Insert (ReplacePath,AreaData.FidoMsgPath,1);

               { RWI 201094: Write binnen IF gehaald. Alleen schrijven bij }
               {             change in directory.                          }
               WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
          END;
     END; { for }

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeType                                                      }
{                                                                          }
{ Zorgt ervoor dat je het type van een groupje areas kan veranderen.       }
{ mogenlijk zijn Echomail, Netmail & Local.                                }
{                                                                          }
PROCEDURE AreaGlob_ChangeType;

VAR NewType  : AreaRecordType;
    AreaLoop : LONGINT;

BEGIN
     MenuDefine (3,3,'Select a new area type for the selected areas');
     MenuAddItem ('Echomail');
     MenuAddItem ('Netmail');
     MenuAddItem ('Local');
     MenuAddItem ('E-mail');
     MenuSetHelp (htr_AreaGlobEdit_ChangeAreaType);

     MenuShow;
     CASE MenuSelect OF
          kEsc : BEGIN
                      MenuErase;
                      Exit;
                 END;

          mOpt01 : NewType:=Area_Echo;
          mOpt02 : NewType:=Area_Netmail;
          mOpt03 : NewType:=Area_Local;
          mOpt04 : NewType:=Area_EMail;
     END;

     MenuErase;
     Message ('Updating Area Records with new area type');

     FOR AreaLoop:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
          AreaData.AreaType:=NewType;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLoop),AreaData);
     END;

     WindowPop;
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeDupeAge                                                   }
{                                                                          }
{ This routine allows you to change the dupe age for all the tagged areas  }
{ in one run.                                                              }
{                                                                          }
PROCEDURE AreaGlob_ChangeDupeAge;

CONST Xb = 15;
      Yb = 10;
      Xl = 32;
      Yl = 5;

VAR AreaLp : LONGINT;
    NewAge : BYTE;
    Nop    : ValNop;
    Str    : STRING[3];

BEGIN
     FieldPushAll;

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

     WriteXY (Xb+2,Yb+2,'New dupe history     (weeks)');

     FieldInit;

     Str:='   ';

     FieldAutoDefineOne (Xb+19,Yb+2,@Str,'%%%');
     FieldSetHelp (1,htr_AreaGlobEdit_ChangeDupeHistory);

     FieldEditDirect;

     WindowPop; { edit window }
     FieldPopAll;

     IF (Key = kEsc) THEN
        Exit;

     Val (DeleteFrontAndBackSpaces (Str),NewAge,Nop);
     IF (Nop <> 0) THEN
     BEGIN
          Error ('Invalid entry');
          Exit;
     END;

     Message ('Updating Area Records...');

     FOR AreaLp:=1 TO ListTagCount DO
     BEGIN
          ReadAreaBaseRecord (ListGetTaggedItemNr (AreaLp),AreaData);
          AreaData.DupeAge:=NewAge;
          WriteAreaBaseRecord (ListGetTaggedItemNr (AreaLp),AreaData);
     END;

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeCharSet                                                   }
{                                                                          }
{ This routine allows to select a new FTN or RFC character set for all the }
{ tagged areas.                                                            }
{                                                                          }
PROCEDURE AreaGlob_ChangeCharSet (FTNSet : BOOLEAN);

VAR SetName   : STRING;
    AreaRec   : AreaBaseRecord;
    AreaRecNr : AreaBaseRecordNrType;
    AreaLp    : WORD;

BEGIN
     SetName:='';
     IF CharSets_PickList (NOT FTNSet,SetName) THEN
        Exit; { aborted }

     Message ('Updating Area Records...');

     FOR AreaLp:=1 TO ListTagCount DO
     BEGIN
          AreaRecNr:=ListGetTaggedItemNr (AreaLp);
          ReadAreaBaseRecord (AreaRecNr,AreaRec);

          IF FTNSet THEN
             AreaRec.CharSet_FTN:=SetName
          ELSE
              AreaRec.CharSet_RFC:=SetName;

          WriteAreaBaseRecord (AreaRecNr,AreaRec);
     END;

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeDecodeOption                                              }
{                                                                          }
{ This global menu option allows to change the File Decoding option to     }
{ Not or On Import for all the tagged areas.                               }
{                                                                          }
PROCEDURE AreaGlob_ChangeDecodeOption;

VAR NewDecode : BOOLEAN;
    AreaRec   : AreaBaseRecord;
    AreaRecNr : AreaBaseRecordNrType;
    AreaLp    : WORD;

BEGIN
     MenuDefine (3,3,'Select a new decode option for the selected areas');
     MenuAddItem ('No decoding of attachments');
     MenuAddItem ('Decode attachment when message is imported into a local message base');
     {MenuSetHelp (htr_AreaGlobEdit_...);}

     MenuShow;
     CASE MenuSelect OF
          kEsc : BEGIN
                      MenuErase;
                      Exit;
                 END;

          mOpt01 : NewDecode:=FALSE;
          mOpt02 : NewDecode:=TRUE;
     END;

     MenuErase;

     Message ('Updating Area Records...');

     FOR AreaLp:=1 TO ListTagCount DO
     BEGIN
          AreaRecNr:=ListGetTaggedItemNr (AreaLp);
          ReadAreaBaseRecord (AreaRecNr,AreaRec);

          AreaRec.Decode:=NewDecode;

          WriteAreaBaseRecord (AreaRecNr,AreaRec);
     END;

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaGlob_ChangeDecodePath                                                }
{                                                                          }
{ This global menu option allows to change the decode path to a new path   }
{ picked with the file manager, for all the tagged areas.                  }
{                                                                          }
PROCEDURE AreaGlob_ChangeDecodePath;

CONST Xb = 10;
      Yb = 10;
      Xl = 50;
      Yl = 6;

VAR NewPath   : STRING;
    AreaRec   : AreaBaseRecord;
    AreaRecNr : AreaBaseRecordNrType;
    AreaLp    : WORD;

BEGIN
     FieldPushAll;

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

     WriteXY (Xb+2,Yb+2,'New decode path: ');

     NewPath:=Spaces (MaxLenPath);

     FieldInit;
     FieldAutoDefineFileMgr (Xb+19,Yb+2,40,@NewPath,PathFileMgr,{AllowSearchChars}FALSE);
     FieldSetHelp (0,htr_AreaEdit_FilesPath);
     FieldEditDirect;

     WindowPop;

     FieldPopAll;

     IF (Key = kEsc) THEN
        Exit;

     NewPath:=DeleteFrontAndBackSpaces (NewPath);

     Message ('Updating Area Records...');

     FOR AreaLp:=1 TO ListTagCount DO
     BEGIN
          AreaRecNr:=ListGetTaggedItemNr (AreaLp);
          ReadAreaBaseRecord (AreaRecNr,AreaRec);

          AreaRec.DecodePath:=NewPath;

          WriteAreaBaseRecord (AreaRecNr,AreaRec);
     END;

     WindowPop; { message }
END;


{--------------------------------------------------------------------------}
{ AreaListGlobalMenu                                                       }
{                                                                          }
{ Globale functies om het bijhouden van de area configuratie makkelijker   }
{ te maken.                                                                }
{                                                                          }
PROCEDURE AreaListGlobalMenu;
BEGIN
     { Kijk of er wel areas geselecteerd zijn, zo nee spring terug }
     IF (ListTagCount = 0) THEN
     BEGIN
          Error2Lines ('To use the global option, you have to tag at least one area!',
                       '(use F5, F6 and F7 for tagging)');
          Exit;
     END;

     MenuDefine (3,3,'Area global changes');
     MenuAddItem ('Change area type');
     MenuAddItem ('Change area origin AKA');
     MenuAddItem ('Change SEEN-BY list');
     MenuAddItem ('Change custom origin line');
     MenuAddItem ('Change default origin line');
     MenuAddItem ('Change message base age');
     MenuAddItem ('Change message base limits');
     MenuAddItem ('Change message base type');
     MenuAddItem ('Change message base directories');
     MenuAddItem ('Change dupe history (weeks)');
     MenuAddItem ('Change FTN character set');
     MenuAddItem ('Change RFC character set');
     MenuAddItem ('Change decode option');
     MenuAddItem ('Change decode path');
     MenuSetHelp (htr_AreaGlobEdit_Menu);

     MenuShow;
     MenuSelect;
     MenuErase;

     CASE Key OF
          mOpt01 : AreaGlob_ChangeType;
          mOpt02 : AreaGlob_ChangeOriginAKA;
          mOpt03 : AreaGlob_ChangeSeenBys;
          mOpt04 : AreaGlob_ChangeCustomOrigin;
          mOpt05 : AreaGlob_ChangeDefaultOrigin;
          mOpt06 : AreaGlob_ChangeBaseAge;
          mOpt07 : AreaGlob_ChangeBaseLimits;
          mOpt08 : AreaGlob_ChangeBaseType;
          mOpt09 : AreaGlob_ChangeDirectory;
          mOpt10 : AreaGlob_ChangeDupeAge;
          mOpt11 : AreaGlob_ChangeCharset (TRUE{=FTN});
          mOpt12 : AreaGlob_ChangeCharset (FALSE{=RFC});
          mOpt13 : AreaGlob_ChangeDecodeOption;
          mOpt14 : AreaGlob_ChangeDecodePath;
     END; { case }
END;


{--------------------------------------------------------------------------}
{ AreaConfigSelective                                                      }
{                                                                          }
{ Van hieruit kunnen de area configs aangepast worden. Alleen de opgegeven }
{ Groups worden ingeladen om tijd en ruimte te besparen.                   }
{                                                                          }
PROCEDURE AreaConfigSelective (GroupsFilter : GroupFlagType);

CONST Xb = 10;
      Yb = 10;
      Xl = 60;
      Yl = 6;
      Xb2 = 40;

TYPE DubRecord = RECORD
                       Low,High : AreaBaseRecordNrType;
                 END;

CONST MAXDUBENTRIES = 1200; { max 16000 }

TYPE DubArray    = ARRAY[1..MAXDUBENTRIES] OF DubRecord; { 4.8k }
     DubArrayPtr = ^DubArray;

VAR DubPtr   : DubArrayPtr;
    DubCount : 0..MAXDUBENTRIES;
    DubCompr : BYTE; { downcounter voor comprimeren van dublist }

    {----------------------------------------------------------------------}
    { AddTheRecNr                                                          }
    {                                                                      }
    { Deze routine voegt een record nummer toe aan de lijst met TheArea    }
    { record nummers. Geeft FALSE terug als er geen ruimte meer is om het  }
    { nummer op te slaan.                                                  }
    {                                                                      }
    FUNCTION AddTheRecNr (ARecNr : AreaBaseRecordNrType) : BOOLEAN;

    VAR Lp,Lp2 : 0..MAXDUBENTRIES;

    BEGIN
         AddTheRecNr:=TRUE; { ruimte gevonden en opgeslagen }

         { voeg toe aan een van de lijsten }
         FOR Lp:=1 TO DubCount DO
             WITH DubPtr^[Lp] DO
             BEGIN
                  IF (ARecNr = Low-1) THEN
                  BEGIN
                       Dec (Low);
                       Exit;
                  END;

                  IF (ARecNr = High+1) THEN
                  BEGIN
                       Inc (High);
                       Exit;
                  END;
             END; { with, for }

         { om zeker te zijn dat er ruimte is, gaan we eerst comprimeren   }
         { als we tegen de limiet aan zitten, of als het gewoon nodig is. }
         Dec (DubCompr);

         IF (DubCompr = 0) OR (DubCount = MAXDUBENTRIES) THEN
         BEGIN
              DubCompr:=50; { voorlopig weer even niet meer nodig }

              Lp:=1;

              WHILE (Lp < DubCount) DO
              BEGIN
                   Lp2:=Lp+1;

                   WHILE (Lp2 <= DubCount) DO
                   BEGIN
                        IF (DubPtr^[Lp].High = DubPtr^[Lp2].Low-1) THEN
                        BEGIN
                             { deze twee kunnen aan elkaar! }
                             DubPtr^[Lp].High:=DubPtr^[Lp2].High;

                             { de laatste kan nu weg. Vervang deze door de }
                             { laatste entry in de lijst en controleer dan }
                             { weer.                                       }

                             { als dit al de laatste was, dan verdwijnt ie }
                             DubPtr^[Lp2]:=DubPtr^[DubCount];
                             Dec (DubCount);

                             Continue; { while lp2 }
                        END;

                        IF (DubPtr^[Lp2].Low = DubPtr^[Lp2].High+1) THEN
                        BEGIN
                             { ze kunnen aan elkaar }
                             DubPtr^[Lp].Low:=DubPtr^[Lp2].Low;

                             DubPtr^[Lp2]:=DubPtr^[DubCount];
                             Dec (DubCount);

                             Continue; { while lp2 }
                        END;

                        { deze kan niet aan die van lp1. Zoek verder }
                        Inc (Lp2);
                   END; { while }

                   { alle mogelijkheden tegen deze geprobeert. Op naar de }
                   { volgende.                                            }
                   Inc (Lp);
              END; { while }
         END;

         { geen range uit kunnen breiden. Maak een nieuwe range aan }
         IF (DubCount = MAXDUBENTRIES) THEN
         BEGIN
              AddTheRecNr:=FALSE; { geen plek meer voor! }
              Exit;
         END;

         Inc (DubCount);
         DubPtr^[DubCount].Low:=ARecNr;
         DubPtr^[DubCount].High:=ARecNr;
    END;


    {----------------------------------------------------------------------}
    { BuildListOfTheAreas                                                  }
    {                                                                      }
    { Deze routine bouwt een lijst op met record nummers die nu getagged   }
    { staan in de lijst, zodat deze lijst straks snel doorlopen kan worden }
    { als de areas geunsubscribed moeten worden.                           }
    { Als er niet genoeg geheugen is om deze lijst aan te leggen, dan      }
    { wordt FALSE terug gegeven en moet het verwijderen op de oude manier  }
    { voortgezet worden.                                                   }
    {                                                                      }
    FUNCTION BuildListOfTheAreas : BOOLEAN;

    VAR Keuze : WORD;

    BEGIN
         IF (_MaxAvail < SizeOf (DubArray)) THEN
         BEGIN
              Error2Lines ('Not enough memory for optimized deletion method',
                           'Old and slow deletion method will be used instead');
              BuildListOfTheAreas:=FALSE; { moet met de hand }
              Exit;
         END;

         Message ('Initializing for rapid delete...');

         GetMem (DubPtr,SizeOf (DubArray));
         PeekMem;

         DubCompr:=50;
         DubCount:=0;

         WHILE (ListTagCount > 0) DO
         BEGIN
              Keuze:=ListGetTaggedItemNr (1);

              IF (NOT AddTheRecNr (Keuze)) THEN
                 Break; { geen plek meer voor }

              ListRemoveItem (Keuze);
         END; { while }

         WindowPop;

         { alle of de meeste records zijn nu toegevoegd }
         BuildListOfTheAreas:=TRUE; { (gedeeltelijk) gelukt }
    END;


    {----------------------------------------------------------------------}
    { DestroyTheAreasList                                                  }
    {                                                                      }
    { Deze routine vernietigt de lijst met TheArea record nummers.         }
    {                                                                      }
    PROCEDURE DestroyTheAreasList;
    BEGIN
         FreeMem (Dubptr,SizeOf (DubArray));
    END;


    {----------------------------------------------------------------------}
    { InTheList                                                            }
    {                                                                      }
    { Deze routine kijkt of het opgegeven nummer voorkomt in de lijst met  }
    { TheRecordNummers en zoja, geeft dan TRUE terug.                      }
    {                                                                      }
    FUNCTION InTheList (RecNr : WORD) : BOOLEAN;

    VAR Lp : 0..MAXDUBENTRIES;

    BEGIN
         FOR Lp:=1 TO DubCount DO
             WITH DubPtr^[Lp] DO
                  IF (RecNr >= Low) AND (RecNr <= High) THEN
                  BEGIN
                       InTheList:=TRUE;
                       Exit;
                  END;

         InTheList:=FALSE;
    END;


    {----------------------------------------------------------------------}
    { UnSubscribeTheAreas                                                  }
    {                                                                      }
    { Deze routine doorloopt de subscription base records van alle users   }
    { en haalt daaruit alle area record nummers die in TheAreas list       }
    { voorkomen, zodat ze geunsubscribed zijn.                             }
    {                                                                      }
    PROCEDURE UnsubscribeTheAreas;

    VAR ULp,
        URecCount : WORD;
        UserRec   : UserBaseRecord;
        SubNr     : SubscriptBaseRecordNrType;
        SubRec    : SubscriptBaseRecord;
        SLp       : 0..MaxSubscrBaseElements;
        PercDone  : BYTE;
        Changed   : BOOLEAN;

    BEGIN
         URecCount:=UserBaseRecCount;

         FOR ULp:=1 TO URecCount DO
         BEGIN
              ReadUserBaseRecord (ULp,UserRec);

              SubNr:=UserRec.AreaList;

              WHILE (SubNr <> NILRecordNr) DO
              BEGIN
                   ReadSubscriptBaseRecord (SubNr,SubRec);
                   Changed:=FALSE;

                   FOR SLp:=1 TO MaxSubscrBaseElements DO
                       IF InTheList (SubRec.AreaList[SLp]) THEN
                       BEGIN
                            SubRec.AreaList[SLp]:=NILRecordNr;
                            Changed:=TRUE;
                       END;

                   IF Changed THEN
                      WriteSubscriptBaseRecord (SubNr,SubRec);

                   SubNr:=SubRec.NextSegmentRecordNr;
              END; { while }

              PercDone:=Round (ULp/URecCount*100);
              WriteXYC (Xb2,Yb+3,cBoxData,Word2String (ULp)+'/'+Word2String (URecCount)+
                                          ' ('+Byte2String (PercDone)+'%)');
         END; { for }
    END;


    {----------------------------------------------------------------------}
    { DeleteTheAreas                                                       }
    {                                                                      }
    { Pas alle records aan van de te verwijderen areas. Markeer ze Deleted }
    { en zet de UserList op NILRecordNr, zodat niemand er meer op          }
    { aangesloten is.                                                      }
    {                                                                      }
    PROCEDURE DeleteTheAreas (KillBase : BOOLEAN);

    VAR DLp      : 0..MAXDUBENTRIES;
        ALp      : WORD;
        Done,
        Sum      : WORD;
        PercDone : BYTE;
        ARec     : AreaBaseRecord;

    BEGIN
         Sum:=0;
         FOR DLp:=1 TO DubCount DO
             WITH DubPtr^[DLp] DO
                  Sum:=Sum+(High-Low+1);

         Done:=0;
         FOR DLp:=1 TO DubCount DO
             WITH DubPtr^[DLp] DO
                  FOR ALp:=Low TO High DO
                  BEGIN
                       DeleteAreaBaseRecord (ALp,KillBase,TRUE{rapid});

                       Inc (Done);
                       PercDone:=Round (Done/Sum*100);
                       WriteXYC (Xb2,Yb+4,cBoxData,Word2String (Done)+'/'+Word2String (Sum)+
                                                   ' ('+Byte2String (PercDone)+'%)');
                  END; { for }
    END;

VAR ItemNr,
    Keuze2,
    Keuze     : WORD;
    KeuzeDel,
    Quit      : BOOLEAN;
    Lp        : AreaBaseRecordNrType;
    GLp       : GroupDescBaseRecordNrType;
    GroupData : GroupDescRecord;
    NewGroup  : GroupNrType;
    PercDone  : BYTE;

BEGIN
     AreaFilter:=GroupsFilter;

     Message ('Reading area names °°°°°°°°°° (0%)  ');

     ListTagKeysLine:=' ^F1 Help ^Esc Abort ^F2 Global ^Ins Create ^Del Remove ^Enter Edit/Move ^Tag ^keys';
     ListDefine (3,3,Video.Cols-10,Video.Rows-4,Default,
                 'Configured Areas for group(s) '+BuildGroupListDesc (GroupsFilter,40),
                 htr_AreaEdit_AreaList);

     ListLowMemLimit:=10000; { dan blijft er nog genoeg voor een group list over }
     FOR Lp:=1 TO AreaBaseRecCount DO
     BEGIN
          ReadAreaBaseRecord (Lp,AreaData);

          PercDone:=Round ((Lp/AreaBaseRecCount)*100);
          WriteXYC (42,MessageYB,cMessage,
                                   RepChar (PercDone DIV 10,'±')+
                                   RepChar (10-(PercDone DIV 10),'°')+
                                   ' ('+Byte2String (PercDone)+'%)');

          IF (NOT AreaData.Deleted) AND (TestIfGroupCommon (AreaData.IsInGroups,GroupsFilter)) THEN
             ListAddItem (AreaData.AreaName_F,Lp,Bottom{Sorted});

          IF KeyPressed AND (ReadKey = kEsc) THEN
          BEGIN
               ListLowMemLimit:=4096; { restore to default }
               WindowPop;
               ListErase;
               Exit;
          END;
     END;
     ListLowMemLimit:=4096; { restore to default }

     WindowPop; { message }

     ListSortNow;

     Quit:=FALSE;
     REPEAT
           { als de dummy niet meer nodig is, dan weghalen }
           IF (ListItemCount = 0) THEN { dummy + items }
              ListAddItem ('<no areas configured>',65534,Bottom);

           Keuze:=ListSelect (DoTag,[kF2,kIns,kDel]);

           ListRemoveItem (65534);

           CASE Key OF

                kF2 : AreaListGlobalMenu;

                kIns :
                    IF (ListTagCount = 0) THEN
                    BEGIN
                         IF CreateNewAreaBaseRecord (GroupsFilter) THEN
                         BEGIN
                              Keuze:=AreaBaseRecCount;
                              ReadAreaBaseRecord (Keuze,AreaData);
                              ListAddItem (AreaData.AreaName_F,Keuze,Sorted);
                              ListSetCursorOnItem (Keuze);
                         END;
                    END;

                kDel :
                    BEGIN
                         IF (ListTagCount = 0) THEN
                         BEGIN
                              IF (Keuze < 65000) AND (AreYouSureWithHelp ('Delete this area?',911) = mOpt01) THEN
                              BEGIN
                                   DeleteAreaBaseRecord (Keuze,DeleteBaseFiles,FALSE);
                                   ListRemoveItem (Keuze);
                              END;
                         END ELSE
                         BEGIN
                              IF (AreYouSureWithHelp ('Delete these areas?',911) = mOpt01) THEN
                              BEGIN
                                   KeuzeDel:=DeleteBaseFiles;

                                   { bouw een lijst op met alle area nummers }
                                   IF (ListTagCount > 15) AND BuildListOfTheAreas THEN
                                   BEGIN
                                        PushKeysLine;
                                        WriteKeysLine (' Please wait...');

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

                                        WriteXY (Xb+2,Yb+1,'Rapid Delete progress');
                                        WriteXY (Xb+2,Yb+3,'[ ] Unsubscribe with users');
                                        WriteXY (Xb+2,Yb+4,'[ ] Mark areas as deleted');

                                        IF (Video.Color) THEN
                                           ModifyColor (cCustom1,cBlue*16+cWhite+cBlink)
                                        ELSE
                                            ModifyColor (cCustom1,mBlack*16+mWhite+mBlink);

                                        WriteXYC (Xb+3,Yb+3,cCustom1,'þ');
                                        UnsubscribeTheAreas;
                                        WriteXYC (Xb+3,Yb+3,cBoxData,'û');

                                        WriteXYC (Xb+3,Yb+4,cCustom1,'þ');
                                        DeleteTheAreas (KeuzeDel);
                                        WriteXYC (Xb+3,Yb+4,cBoxData,'û');

                                        WindowPop;
                                        PopKeysLine;

                                        DestroyTheAreasList;
                                   END;

                                   { als er nu nog areas over zijn, dan }
                                   { verwijderen we die met de oude     }
                                   { method. Dit komt voor als er geen  }
                                   { ruimte is om de record nummers op  }
                                   { te slaan of een paar er niet meer  }
                                   { bij konden.                        }
                                   IF (ListTagCount > 0) THEN
                                   BEGIN
                                        PushKeysLine;
                                        WriteKeysLine (' ^Esc Abort');

                                        Message ('Deleting areas °°°°°°°°°° (0%)  ');

                                        Keuze2:=ListTagCount;
                                        WHILE (ListTagCount > 0) DO
                                        BEGIN
                                             { deze PercDone wordt vOOraf afgedrukt, dus geeft aan }
                                             { met welke we nu bezig zijn. 1*/4 = 25%, etc. zodat  }
                                             { 100% ook in beeld komt.                             }
                                             PercDone:=Round (((Keuze2-ListTagCount+1)/Keuze2)*100);
                                             WriteXYC (40,MessageYB,cMessage,
                                                                      RepChar (PercDone DIV 10,'±')+
                                                                      RepChar (10-(PercDone DIV 10),'°')+
                                                                      ' ('+Byte2String (PercDone)+'%)');

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

                                             Keuze:=ListGetTaggedItemNr (1);
                                             ListRemoveItem (Keuze);

                                             DeleteAreaBaseRecord (Keuze,KeuzeDel,FALSE{not rapid});
                                        END; { while }

                                        WindowPop; { message }
                                        PopKeysLine;
                                   END; { oude delete methode nodig }

                              END; { sure to remove }
                         END; { multiple tagged? }
                    END; { kDel }

                kRet :
                    IF (ListTagCount <> 0) THEN
                    BEGIN
                         { global change groups }
                         ListDefine (40,3,37,Video.Rows-4,Default,
                                     'Select a new group',
                                     htr_AreaEdit_SelectNewGroup);

                         FOR GLp:=1 TO MaxGroups DO
                         BEGIN
                              ReadGroupDescRecord (GLp,GroupData);
                              ListAddItem (BuildGroupDesc (GLp,GroupData),GLp,Bottom);
                              {
                              GroupData.GroupDesc:=DeleteBackSpaces (GroupData.GroupDesc);
                              IF (GroupData.ReadOnly) THEN
                                 ListAddItem (Chr (64+GLp)+': [READ-ONLY] '+GroupData.GroupDesc,GLp,Bottom)
                              ELSE
                                  ListAddItem (Chr (64+GLp)+': '+GroupData.GroupDesc,GLp,Bottom);
                              }
                         END;

                         Keuze2:=ListSelect (NoTag,[]);

                         ListErase;

                         IF (Key = kRet) THEN
                         BEGIN
                              Message ('Moving areas to new group °°°°°°°°°° (0%)  ');

                              ReadGroupDescRecord (Keuze2,GroupData);
                              NewGroup:=Keuze2;

                              Lp:=ListTagCount; { reminder }
                              WHILE (ListTagCount > 0) DO
                              BEGIN
                                   Keuze:=ListGetTaggedItemNr (1);

                                   ReadAreaBaseRecord (Keuze,AreaData);
                                   ResetGroupFlags (AreaData.IsInGroups);
                                   AddGroupToGroupList (AreaData.IsInGroups,NewGroup);

                                   { groep alleen uit de lijst halen als ie na de }
                                   { verplaatsing niet meer in de set hoort. Dit  }
                                   { move naar zelfde groep niet uit de lijst te  }
                                   { halen.                                       }
                                   IF TestIfInGroup (GroupsFilter,NewGroup) THEN
                                      ListUntagItem (Keuze)
                                   ELSE
                                       ListRemoveItem (Keuze);

                                  {AreaData.OriginAka:=GroupData.OriginAka;}
                                  {AreaData.SeenByAkas:=(1 SHL (Keuze2-1));}
                                   WriteAreaBaseRecord (Keuze,AreaData);

                                   PercDone:=Round (((Lp-ListTagCount)/Lp)*100);
                                   WriteXYC (45,MessageYB,cMessage,
                                                            RepChar (PercDone DIV 10,'±')+
                                                            RepChar (10-(PercDone DIV 10),'°')+
                                                            ' ('+Byte2String (PercDone)+'%)');
                              END; { while }

                              WindowPop; { message }
                         END;
                    END ELSE
                        { record editten in plaats van moven }
                        IF EditAreaBaseRecord (Keuze) THEN
                        BEGIN
                             { naam is gewijzigd }
                             ReadAreaBaseRecord (Keuze,AreaData);
                             ListRemoveItem  (Keuze);
                             ListAddItem (AreaData.AreaName_F,Keuze,Sorted);
                             ListSetCursorOnItem (Keuze);
                        END;

                kEsc : Quit:=TRUE;

           END; { case }

     UNTIL Quit;

     ListErase;
     ListTagKeysLine:=ORG_ListTagKeysLine;
END;


{--------------------------------------------------------------------------}
{ AreaConfigs                                                              }
{                                                                          }
{ Van hieruit kunnen de area configs aangepast worden.                     }
{                                                                          }
PROCEDURE AreaConfigs;

CONST ReadOnlyStrs : ARRAY[FALSE..TRUE] OF STRING[12] = ('','[READ-ONLY] ');

VAR Groups    : GroupFlagType;
    Lp        : AreaBaseRecordNrType;
    Keuze     : WORD;
    GroupData : GroupDescRecord;
    Quit      : BOOLEAN;

BEGIN
     ListDefine (3,3,Video.Cols-10,Video.Rows-4,Default,
                 'Select group(s)',
                 htr_AreaEdit_GroupsList);

     FOR Lp:=1 TO MaxGroups DO
     BEGIN
          ReadGroupDescRecord (Lp,GroupData);
          ListAddItem (BuildGroupDesc (Lp,GroupData),Lp,Bottom);
     END; { for }

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

           CASE Key OF
                kEsc : Quit:=TRUE;

                kRet : BEGIN
                            ResetGroupFlags (Groups);  { no groups selected yet }
                            IF (ListTagCount = 0) THEN
                               AddGroupToGroupList (Groups,Keuze)
                            ELSE BEGIN
                                 FOR Lp:=1 TO ListTagCount DO
                                     AddGroupToGroupList (Groups,ListGetTaggedItemNr (Lp));
                            END;

                            AreaConfigSelective (Groups);
                       END;
           END; { case }
     UNTIL Quit;

     ListErase;
END;

{$ENDIF} { WtrConf }

{--------------------------------------------------------------------------}
{ unit initialization                                                      }
{                                                                          }
BEGIN
     NewAreasCreated:=0;
END.
