{ WaterGate Developers Kit for release 0.93 }
{ database structures }

{ include this file from one of your source files with $I structs.pas   }

{ this file describes the structures of WaterGate's database. There is  }
{ no code in header, but just the declarations of the structures. There }
{ _is_ a whealth of explanation in this file though!                    }

{ History:

  950903 0.19     - Initial release.
  950918 0.19.p2  - The config structure in the original release was a
                    complete mess and unusable.
  951030 0.20     - Added administrator fields.
  951203 0.21     - New list server user type, longer time zone string,
                    export AKA in user record.
  960214 0.90     - Config: Log9->LogAreaFix and Log10->LogMapApply.
                    UUCPForwardRecord: reduced path length by 1 and
                    added Group letter.
  960530 0.91     - AreaBase: Added fields for decoding files.
                    Config: Log11..Log14 are now used.
                    New fields for config: CopyHeaders_FU, MailGrade,
                    NewsGrade, TimeSlicing, NetmailDecode,
                    NetmailDecodePath, PrivateDecode, PrivateDecodPath.
  961014 0.92     - Config: Log15 and Log16 are now used, Added RAR
                    support, more system node numbers, more copy header
                    entries, more areafix/newsfix forward entries,
                    remove unused fields.
                    ListServer: Added Access and DefaultAccess.
                    UserBase: Added BAG and SMTP variant record entry.
                    AreaBase: Seen-BY akas now support 100 bits.
  960706 0.93     - New groups format and lots of other changes.
                    AreaBase 04->07: Changed IsInGroups, Added Hidden.
                    Updated groups explanation.
                    UserBase 05->08: Removed unused longint. Changed
                    groups, added envelope header.
                    ListServer 03->05: Added re-confirmation fields,
                    added MLAddress, added confirm interval.
                    Config 14->22: Changed Default_F and Default_U,
                    removed ConversionTable, Added SmtpForward,
                    MaxXPostNewsGroups, WildCatMSGLockDir, OpusDateFormat,
                    MaxWildCatMsgLen, KillAreafixMsgs, Color set.
}

{ I have reduced all the types and constants we use, to make it easier  }
{ for you to read the structures. The names used end with _F if it is   }
{ Fidonet related, and with _U if it is UUCP/Usenet related. _B is BAG, }
{ _S is SMTP and _P is POP3.                                            }

{==========================================================================}
{                  ABOUT THE DATABASES                                     }
{==========================================================================}

{ WaterGate uses six binary database files and one ascii configuration  }
{ file. This source file only covers the six binary databases. Each of  }
{ the database files starts of with a 26 byte long header, which is     }
{ basically a string that is written to disk, including the length byte }
{ at the first position. The string is thus declared as a STRING[25].   }
{ Each database has its own header, as defined below. The last two      }
{ digits are a modification counter, which is increased by one very     }
{ time the database structures change. You have to check this header    }
{ and it has to match exactly, or else you should not access the        }
{ databases with the structures in this file!                           }

CONST AreaBaseHeader     = 'WtrGate AreaBase 07';
      UserBaseHeader     = 'WtrGate UserBase 08';
      SubscrBaseHeader   = 'WtrGate SubscrBase 01';
      GrpDescrBaseHeader = 'WtrGate GroupDescr 03';
      ListServerHeader   = 'WtrGate ListServer 05';
      ConfigHeader       = 'WtrGate Config 22';

{ Directly after this string, the first record starts. All record       }
{ numbering is 1..n, with the special value 65535 meaning a NIL pointer }
{ record, mostly used to indicate free positions or the end of a list   }
{ of record numbers.                                                    }

CONST NILRecordNr : WORD = 65535;

{ to find out how many records are present in a database, you use the   }
{ following formule:                                                    }
{                                                                       }
{ RecCount = ((FileSize (Database)-26) DIV SizeOf (Record));            }
{                                                                       }
{ This formula can be used for each of the databases. Simply substitute }
{ "Record" with the correct structure name and "Database" with the      }
{ actual file variable. It is best to declare the file variable as a    }
{ FILE and to open the database with a Reset (Database,1), as below:    }
{                                                                       }
{ VAR AreaFile : FILE;                                                  }
{     RecCount : WORD;                                                  }
{                                                                       }
{ BEGIN                                                                 }
{      Assign (AreaFile,'AREABASE.TDB');                                }
{      Reset (AreaFile,1);                                              }
{      BlockRead (AreaFile,Header,26);                                  }
{      RecCount:=(FileSize (AreaFile)-26) DIV SizeOf (AreaBaseRecord)); }
{      Close (AreaFile);                                                }
{ END                                                                   }
{                                                                       }
{ To read and write a record, you substract 1 from the record number,   }
{ multiply it with the record size and add 26, then seek to that        }
{ position in the file and read or write the record, like this:         }
{                                                                       }
{ VAR AreaRec   : AreaBaseRecord;                                       }
{     AreaRecNr : WORD;                                                 }
{     Position  : LONGINT;                                              }
{                                                                       }
{ BEGIN                                                                 }
{      Position:=26+Longint (AreaRecNr-1)*SizeOf (AreaBaseRecord);      }
{      Seek (AreaFile,Position);                                        }
{      BlockRead (AreaFile,AreaRec,SizeOf (AreaBaseRecord));            }
{ END;                                                                  }

{==========================================================================}
{                  GLOBAL STRUCTURES                                       }
{==========================================================================}

{ this structure is used to hold an AKA, whereever required }

TYPE FidoAddrType = RECORD
                          Zone   : WORD;
                          Net    : WORD;
                          Node   : WORD;
                          Point  : WORD;
                          Domain : STRING[25];
                    END;

{==========================================================================}
{                  GROUP DESCRIPTIONS DATABASE                             }
{==========================================================================}

{ this database contains 128 records, one for each of the groups. Each }
{ record hold the description of the group, the system AKA to use,     }
{ which is an index number from 1 to 100 in the array of system AKAs   }
{ in the Configuration Record. And finally it contains the ReadOnly    }
{ boolean, which is set to TRUE to disable posting to any area in this }
{ group, unless the user and the area are both in read/write group as  }
{ well.                                                                }

TYPE GroupDescRecord = RECORD
                             GroupDesc : STRING[30];
                             OriginAka : BYTE;         { 1..100 }
                             Readonly  : BOOLEAN;
                       END;

{ old groups storage (<0.93):                                          }
{ to reduce storage space, a LONGINT is used to make a list of groups  }
{ that a user is allowed in, for example. Each bit in the LONGINT      }
{ represents one group, starting with bit 0 for group A up to bit 26   }
{ for group Z. It is kind of tricky to check these groups, as pascal   }
{ does everything in integers, so here are some code example:          }
{                                                                      }
{ Add a group (1..26) to the longint:                                  }
{   Group:=Group OR Longint (1) SHL (NewGroupNr-1);                    }
{                                                                      }
{ Remove a group (1..26) from a longint:                               }
{   CONST GR_ALL = $03FFFFFF                                           }
{   Group:=Group AND (GR_ALL - (Longint (1) SHL (DelGroupNr-1)));      }
{                                                                      }
{ Test if a group (1..26) is in a longint:                             }
{   TestIfInGroup:=(Group AND (Longint (1) SHL (TestGroupNr-1)) > 0);  }
{                                                                      }

{ new groups storage (0.93):                                           }
{                                                                      }
{ there are 128 groups, numbered 1 to 128. The AreaBase.IsInGroups     }
{ and UserBase.Groups are 16 byte arrays, where each byte represents   }
{ subscription to one group. Bit 0 in the first byte is group 1, etc.  }

CONST MaxGroups     = 128;  { A1-5,B1-5,..,Y1-5,Z1-3 }
      GroupFlagLen  = MaxGroups DIV 8;

TYPE GroupFlagType  = ARRAY[1..GroupFlagLen] OF BYTE; { bit mask }


{ to access to groups, use the GroupFlagType and the following code    }
{ sequence to access the group list.                                   }
{                                                                      }
{ VAR I,O : BYTE;                                                      }
{                                                                      }
{ I:=1+((NewGroupNr-1) DIV 8);                                         }
{ O:=(NewGroupNr-1) MOD 8;                                             }
{ Group[I]:=Group[I] OR (1 SHL O);                                     }
{                                                                      }
{ The above example adds NewGroupNr (1..128) by settings the correct   }
{ bit in the array. I is an index into the array and O is the bit      }
{ number ("offset", 0..7).                                             }
{                                                                      }
{ You can use constructions with AND to reset a bit. I have created    }
{ abstract functions to access a GroupFlagType for resetting it,       }
{ adding a single group, removing a single group, testing for          }
{ membership, set overlap tests, etc.                                  }


{==========================================================================}
{                  AREABASE                                                }
{==========================================================================}


TYPE AreaBaseRecord = RECORD
                            { TRUE = Deleted }
                            Deleted      : BOOLEAN;

                            { 0=Echo, 1=Netmail, 2=Local, 3=Email }
                            AreaType     : BYTE;

                            { the two names of this area }
                            AreaName_U,
                            AreaName_F   : STRING[60];

                            { the comment / description }
                            Comment      : STRING[60];

                            { the groups this area is in. See the group }
                            { descriptions database for an explanation. }
                            IsInGroups   : ARRAY[1..16] OF BYTE;

                            { points to the first subscription base }
                            { record. See explanation there.        }
                            UserList     : WORD;

                            { the system AKA to use for the origin line, }
                            { is an index 1..20 into the array in the    }
                            { configuration record.                      }
                            OriginAKA    : BYTE;

                            { The system AKAs 1..100 to add to the SEEN-BY }
                            { If the bit is set, it is added. [0]bit0 is   }
                            { AKA 1, [0]bit1 2, etc.                       }
                            AddSeenByAKAs : ARRAY[0..12] OF BYTE;

                            { TRUE if this area is passive }
                            Passive      : BOOLEAN;

                            { TRUE if this area is allowed to be passive }
                            AlwPassive   : BOOLEAN;

                            { origin number to use: 0=custon, 1/2=system }
                            OriginNr     : BYTE;

                            { the custom origin line }
                            Origin       : STRING[61];

                            { the style of this area's message base }
                            { 0=None, 1=Msg, 2=Squish, 3=Jam, 4=WildCat }
                            FidoMsgStyle : BYTE;

                            { the path to the database }
                            FidoMsgPath  : STRING[79];

                            { the maximum age of a message, when cleaning }
                            FidoMsgAge   : INTEGER;

                            { the max. number of messages in allowed after }
                            { clean-up.                                    }
                            FidoMsgLimit : INTEGER;

                            { is this area moderated? 0=No, 1=Usenet }
                            Moderated    : BYTE;

                            { the e-mail address of the moderator }
                            Moderator    : STRING[50];

                            { XX/UU/MIME decode? }
                            Decode       : BOOLEAN;

                            { path where to store decoded files }
                            DecodePath   : STRING[79];

                            { if TRUE then doesn't show up in AreaFix/newsfix }
                            Hidden       : BOOLEAN;
                      END;

{==========================================================================}
{                  USERBASE                                                }
{==========================================================================}

{ the userbase holds all the users that are configured in WtrConf. There }
{ is one record for each user. The maximum number of records is 65534.   }

TYPE UserBaseRecord = RECORD
                            { TRUE means deleted }
                            Deleted         : BOOLEAN;

                            { 0=Fido, 1=Usenet, 2=Bag supplier }
                            System          : BYTE;

                            { description of this user }
                            Organization    : STRING[60];

                            { the groups this user is allowed in }
                            { see the group description database }
                            { for an explanation of the storage. }
                            Groups          : ARRAY[1..16] OF BYTE;

                            { is this user passive? }
                            Passive         : BOOLEAN;

                            { its AreaFix/newsfix password }
                            AreaFixPwd      : STRING[20];

                            { TRUE = allow special AreaFix commands }
                            AllowFrom       : BOOLEAN;

                            { TRUE = allow new area creation }
                            AllowCreate     : BOOLEAN;

                            { TRUE if this user is allowed to have sub-domains }
                            AllowSubDomains : BOOLEAN;

                            { pointer to the first subscription base }
                            { record, holding the areas this user is }
                            { subscribed to. See the subscription    }
                            { base for an explanation.               }
                            AreaList        : WORD;

                            { the user's UUCP name }
                            UUCPName        : STRING[10];

                            { World Registered UUCP name? }
                            WorldReg        : BOOLEAN;

                            { domain names }
                            Domains         : ARRAY[1..6] OF STRING[50];

                            CASE INTEGER OF

                                      { AKA }
          { FidoNet style user } 0 : (Address      : FidoAddrType;

                                      { full name of the sysop }
                                      Sysop        : STRING[50];

                                      { password to put in *.PKT files }
                                      { and to check in incoming files }
                                      PacketPwd    : STRING[8];

                                      Compression  : BYTE;

                                      { maximum length of an .PKT files }
                                      { before it is cut off and packed }
                                      MaxPktLength : LONGINT;

                                      { the send condition: 0=Normal, }
                                      { 1=Hold, 2=Crash, 3=Direct.    }
                                      SendFormat   : BYTE;

                                      { day-of-week used on the last sent }
                                      { archive. 0=first, 1..7 = dow.     }
                                      LastArchDow  : BYTE;

                                      { last archive number used (TU0,TU1) }
                                      LastArchNr   : BYTE;

                                      { Export AKA. 0=Auto, 1..100=System AKA }
                                      ExportAKA    : BYTE;

                                      { TRUE = decode files for this user? }
                                      DecodeFiles  : BOOLEAN
                                     );

                                     { UUCP/Bag style user specific fields }

                                      { compression to use: 0=None, }
                                      { 1=Compress, 2=Zip.          }
             { UUCP Style User } 1 : (Compress     : BYTE;

                                      { TRUE= add CunBatch to compressed archive }
                                      CunBatch     : BOOLEAN;

                                      { grades for UUCP }
                                      MailGrade    : CHAR;
                                      NewsGrade    : CHAR;

                                      { TRUE = create GIGOT compatible .XQT files }
                                      GigoT        : BOOLEAN;
                                     );

                                      { uucp name of the bag return system }
              { BAG style user } 2 : (BAGbacklink  : STRING[10];

                                      { Search path for the bag files }
                                      BagPath      : STRING[79]
                                     );

                                      { where to process .WRK/.TXT files from }
            { SMTP mailer link } 3 : (SmtpInPath   : STRING[79];

                                      { where to create .WRK/.TXT files }
                                      SmtpOutPath  : STRING[79]
                                     );

                                      { where is the POP3 file stored? }
           { POP3 mailbox link } 4 : (Pop3File     : STRING[79];

                                      { single recipient address }
                                      Recipient    : STRING[50];

                                      { separator searched for }
                                      Separator    : STRING[15];

                                      { envelope header searched for }
                                      EnvelopeHdr  : STRING[25];
                                     );

                                      { search for .PKT files from BBS tosser here }
                        { BBS }  5 : (Inbound      : STRING[79];

                                      { create .PKT files for BBS tosser here }
                                      Outbound     : STRING[79];

                                      { 1..100 }
                                      SystemAKA    : BYTE;

                                      { fake AKA }
                                      FakeZone     : WORD;
                                      FakeNet      : WORD;
                                      FakeNode     : WORD;

                                      { extension for inbound packets (PKT/OUT) }
                                      InboundExt   : STRING[3];

                                      { TRUE = keep SEEN-BY and PATH? }
                                      { FALSE = replace them }
                                      KeepSBP      : BOOLEAN;

                                      { unused }
                                      Reserved1    : BYTE;
                                     );
                      END;

{==========================================================================}
{                  SUBSCRIPTIONS DATABASE                                  }
{==========================================================================}

{ the subscription base is a very simple, but very powerful database. It }
{ is used to store both the areas that a user has connect, but also the  }
{ other way around: the users that are connect to an area.

{ the information is stored in groups of 5 record numbers. From the area }
{ base record, the UserList field holds the first subscription base      }
{ record number, which holds the first five user record numbers. If more }
{ users are connected to an area, then the NextSegmentRecordNr must be   }
{ used to read the next subscription base record with the next five user }
{ record numbers. If there are no more subscription base records, then   }
{ NextSegmentRecordNr holds the value NILRecordNr (65535).               }

{ the same thing applies for the users. The field AreaList in the user   }
{ base record points to the first subscription base record, which holds  }
{ the first five record numbers of the areas that are connected. If an   }
{ area is disconnected, then one of the five record numbers is set to    }
{ NILRecordNr, to indicate a free position. WtrUtil, Pack Databases can  }
{ clean this up and pack more subscription base records that hold only a }
{ few record numbers into one subscription base record.                  }

{ It is possible to have a NILRecordNr in the UserList or AreaList field }
{ of the userbase/areabase records. In that case, there are no           }
{ subscription base record to read and there are no users or areas       }
{ connected.                                                             }

TYPE SubscriptBaseRecord = RECORD
                                 NextSegmentRecordNr : WORD;

                                 CASE INTEGER OF
                                      0 : (UserList : ARRAY[1..5] OF WORD);
                                      1 : (AreaList : ARRAY[1..5] OF WORD);
                           END;

{ to complete it, a small picture:            }
{                                             }
{ Userbase record:                            }
{       AreaList                              }
{         |                                   }
{         V                                   }
{ Subscription base record:                   }
{       AreaList[1.5]      -----> AreaBase    }
{       NextSegmentRecordNr                   }
{         |                                   }
{         V                                   }
{ Subscription base record:                   }
{       AreaList[1..5]     -----> AreaBase    }
{       NextSegmentRecordNr                   }
{        _|_ (NILRecordNr)                    }
{                                             }

{==========================================================================}
{                  CONFIGURATION DATABASE                                  }
{==========================================================================}

{ structures for the system configuration database. There is only one  }
{ record in this database. The structures below start with the areafix }
{ and newsfix forwarding records, which are used in the configuration  }
{ record. I have removed all other references and put them straigt in. }

{ Since AreaFix and newsfix forwarding have not been re-implemented    }
{ yet, I have not described the structures, until they become certain. }

TYPE AreafixForwardRecord = RECORD
                                  { uplink AKA }
                                  UplinkAddress : FidoAddrType;

                                  { allow all new names, or check against file? }
                                  Unconditional : BOOLEAN;

                                  { path to the forwarding file }
                                  AreaListPath  : STRING[50];

                                  { type of the file. 0=areas.bbs, 1=names list }
                                  AreaList      : BYTE;

                                  { name of uplink's AreaFix }
                                  AreaManager   : STRING[10];

                                  { password for uplink's areafix }
                                  Password      : STRING[10];

                                  { group to put new areas in. 0 = Group A1 }
                                  Group         : BYTE;

                                  { Add "+" to connect in front of areaname }
                                  AddPlus       : BOOLEAN;
                            END;

TYPE UUCPForwardRecord  = RECORD
                                { UUCPname of uplink }
                                UUCPName     : STRING[10];

                                { path to the newsgroups listing }
                                AreaListPath : STRING[49];

                                { group to put new areas in. 0 = Group A1 }
                                Group        : BYTE;
                          END;

TYPE ConfigRecord = RECORD
                          { path to the other databases }
                          SystemDir           : STRING[79];

                          { full name of the sysop }
                          Sysop               : STRING[50];

                          { max. number of dupes to remember (16000 max.) }
                          DupeChecks          : WORD;

                          { TRUE = Check for dupes }
                          DoDupeChk           : BOOLEAN;

                          { max. number of outbound files to keep open }
                          MaxHandles          : BYTE;

                          { TRUE cache the databases in XMS }
                          CacheTdbs           : BOOLEAN;

                          { path to the too-large directory for oversized msgs }
                          TooLargePath        : STRING[79];

                          { path and filename of the logfile and stats file }
                          LogFilePath         : STRING[79];

                          { system AKAs }
                          NodeNrs             : ARRAY[1..100] OF FidoAddrType;

                          { pointnet for each of the system AKAs }
                          PointNets           : ARRAY[1..100] OF WORD;

                          { Secure the inbound paths: 0=Yes, 1=No }
                          Security_F          : ARRAY[1..2] OF BYTE;

                          { paths to the inbound directories }
                          Inbound_F           : ARRAY[1..2] OF STRING[79];

                          { path to the outbound directory }
                          Outbound_F          : STRING[79];

                          { Fido compress/decompression programs    }
                          { 1st: 0=compress, 1=decompress           }
                          ComprPrgs_F         : ARRAY[0..1,0..8] OF STRING[79];

                          MaxFidoMsgLen       : LONGINT;

                          MaxFidoArcLen       : LONGINT;

                          { default groups for a new Fido user }
                          DefGroups_F         : ARRAY[1..16] OF BYTE;

                          { 0=Binkley, 1=Frontdoor, 2=dBridge }
                          FidoSystem          : BYTE;

                          { scan the To: field for a e-mail address? }
                          FidoAcceptTO        : BOOLEAN;

                          { Netmail msgbase type: 0=None, 1=Msg, 2=Squish, 3=Jam }
                          FidoNetmailType     : BYTE;

                          { path to the database }
                          FidoNetmailPath     : STRING[79];

                          { Bad msgbase type: 0=None, 1=Msg, 2=Squish, 3=Jam }
                          FidoBadAreaType     : BYTE;

                          { path to the database }
                          FidoBadPath         : STRING[79];

                          { Dupe msgbase type: 0=None, 1=Msg, 2=Squish, 3=Jam }
                          FidoDupeAreaType    : BYTE;

                          { path to the database }
                          FidoDupePath        : STRING[79];

                          { New created areas type: 0=None, 1=Msg, 2=Squish, 3=Jam }
                          FidoAutoCreateType  : BYTE;

                          { default path to use (no filename) }
                          DefaultFidoMsgPath  : STRING[79];

                          { TRUE = strip seen-bys when importing }
                          StripSeenBy         : BOOLEAN;

                          { TRUE = link after import }
                          AutoLink            : BOOLEAN;

                          { replace the tearline when exporting? }
                          ReplaceTear         : BOOLEAN;

                          { default number of msgs to keep for an new area }
                          DefNumbToKeep_F     : INTEGER;

                          { default number of days to keep msgs for a new area }
                          DefDaystoKeep_F     : INTEGER;

                          { which arcmail extensions should be used: }
                          { 0=Arc(0..9), 1=Hex(0..9,A..F), 2=All(0..9,A..Z) }
                          FidoArcmailExtension : BYTE;

                          { Gateway AKA nr: 1..10, as index in system AKAs array }
                          UUCPGateway         : BYTE;

                          { character to replace spaces with in user names }
                          { when building an e-mail address.               }
                          NameSeparator       : CHAR;

                          { the two system origin lines }
                          Origins             : ARRAY[1..2] OF STRING[61];

                          { TRUE = system UUCPname is world-reg }
                          WorldWide           : BOOLEAN;

                          { default groups to use for UUCP }
                          DefGroups_U         : ARRAY[1..16] OF BYTE;

                          { path to the spool directories }
                          SpoolBaseDir        : STRING[79];

                          { Max. length of .DAT files, before compression }
                          MaxDatLength        : LONGINT;

                          { UUCPname of your smarthost }
                          SmartHost           : STRING[10];

                          { system UUCP name }
                          UUCPName            : STRING[10];

                          { domain name of the backbone }
                          BackBone            : STRING[50];

                          { system organization line }
                          Organization        : STRING[60];

                          { system domain names }
                          Domains             : ARRAY[1..6] OF STRING[50];

                          { installed compression/decompression programs }
                          { 1st: 0=compress, 1=zip                       }
                          { 2nd: 0=compress, 1=decompress                }
                          ComprPrg_U          : ARRAY[0..1,0..1] OF STRING[79];

                          { type of private mail message base: }
                          { 0=None, 1=*.MSG, 2=Squish, 3=JAM   }
                          PrivmailType        : BYTE;

                          { path to the message base }
                          PrivmailPath        : STRING[79];

                          PrivmailOption      : ARRAY[1..10] OF STRING[72];

                          { where to search: 0=From, 1=To, 2=Subj }
                          PrivmailSelect      : ARRAY[1..10] OF BYTE;

                          AreafixForward      : ARRAY[1..50] OF AreaFixForwardRecord;
                          UUCPForward         : ARRAY[1..50] OF UUCPForwardRecord;

                          { maximum msg length when importing into Squish base }
                          MaxSquishMsgLen     : LONGINT;

                          { maximum msg length when importing into JAM base }
                          MaxJAMMsgLen        : LONGINT;

                          { default compression to set in new user records: }
                          { 0=ARC, 1=ARJ, 2=LZH, 3=PAK, 4=ZIP, 5=ZOO, 6=RAR }
                          { 7=OP1, 8=GUS, 9=PKT.                            }
                          DefaultCompressor   : BYTE;

                          { TRUE = build small e-mail addresses }
                          PackedAddresses     : BOOLEAN;

                          { path to the rescan flag file}
                          RescanFlagFile      : STRING[79];

                          { path to the d'Bridge directory where to store the queueing files }
                          DBridgeQueuePath    : STRING[79];

                          { name of the fido areafix }
                          AreafixName         : STRING[10];

                          { TRUE = automatically kill gated netmail }
                          KillGatedNetmail    : BOOLEAN;

                          { name of the UUCP areafix (newsfix) }
                          NewsfixName         : STRING[10];

                          { TRUE = use a swapfile }
                          UseSwapfile         : BOOLEAN;

                          { path to the swapfile }
                          SwapfilePath        : STRING[79];

                          { maximum length of the swapfile in megabytes }
                          SwapfileSize        : BYTE;

                          { TRUE = create FSC35 reply kludges }
                          ReplyFSC35          : BOOLEAN;

                          { TRUE put the full name in the From: field? }
                          HeaderFullname      : BOOLEAN;

                          { TRUE = enable all other options }
                          LogDebug            : BOOLEAN;

                          { TRUE = log tossed spool files }
                          LogSpoolTossed      : BOOLEAN;

                          { TRUE = log extracted fidonet archives }
                          LogFidoExtract      : BOOLEAN;

                          { TRUE = log tossed fido .PKT files }
                          LogFidoTossed       : BOOLEAN;

                          { TRUE = log built e-mail addressed }
                          LogTranslationFU    : BOOLEAN;

                          { TRUE = log accepted / denied new newsgroup names }
                          LogCheckFilter      : BOOLEAN;

                          { TRUE = log fixed to-address from .X files }
                          LogXFix             : BOOLEAN;

                          { TRUE = Log headers that were copied from fido netmail/echomail messages }
                          LogCopyHeaders      : BOOLEAN;

                          { TRUE = Log found headers that are not allowed }
                          LogIllegalHeaders   : BOOLEAN;

                          { TRUE = Log commands to / replyies from areafix / newsfix }
                          LogAreaFix          : BOOLEAN;

                          { TRUE = Log applied mapping statements }
                          LogMapApply         : BOOLEAN;

                          { TRUE = log all imported netmails }
                          LogNetmailImport    : BOOLEAN;

                          { TRUE = log all read-only denied postings in areas }
                          LogRODeny           : BOOLEAN;

                          { TRUE = log each echomail plus length }
                          LogPktEachEcho      : BOOLEAN;

                          { TRUE = log all created UUCP files }
                          LogUUCPOutbound     : BOOLEAN;

                          { TRUE = log all created SMTP jobs }
                          LogSMTPOutbound     : BOOLEAN;

                          { TRUE = }
                          LogExportedNetmail  : BOOLEAN;

                          { spare ones, so the structs don't need to change all the time }
                          Log17,Log18,Log19,
                          Log20,Log21         : BOOLEAN;

                          { names of the e-mail Headers to search for }
                          { without the trailing space!               }
                          CopyHeaderNames     : ARRAY[1..30] OF STRING[15];

                          { How to store the copied header: }
                          { 0=Not, 1=Kludge, 2=Text         }
                          CopyHeaderHow       : ARRAY[1..30] OF BYTE;

                          { user name of the gateway user }
                          GatewayUser         : STRING[36];

                          { new fields in 0.20 }

                          { TRUE=bounce undeliverable mail }
                          { FALSE=Write to netmail         }
                          BounceUnknown       : BOOLEAN;

                          { TRUE=Send only the first approximate 20 lines }
                          BounceSmall         : BOOLEAN;

                          { Administrator selection }
                          { 0=None, 1=Fido, 2=Usenet }
                          AdminAddrType       : BYTE;

                          { Full name of the administrator, for the Fidonet address }
                          AdminFidoName       : STRING[36];

                          { Fidonet address of the administrator }
                          AdminFidoAddr       : FidoAddrType;

                          { E-mail address of the administrator }
                          AdminUUCPAddr       : STRING[255];

                          { Send the logfile to the administrator? }
                          AdminSendLog        : BOOLEAN;

                          { Spare ones, so the structs don't need changes all the time }
                          AdminSend2,
                          AdminSend3,
                          AdminSend4,
                          AdminSend5,
                          AdminSend6,
                          AdminSend7,
                          AdminSend8,
                          AdminSend9,
                          AdminSend10,
                          AdminSend11,
                          AdminSend12,
                          AdminSend13,
                          AdminSend14,
                          AdminSend15,
                          AdminSend16          : BOOLEAN;

                          { time zone description }
                          TimeZone             : STRING[25];

                          { TRUE = Scan and copy headers Fido->Usenet }
                          CopyHeaders_FU       : BOOLEAN;

                          { grade letter to use in mail job UUCP filenames }
                          MailGrade            : CHAR;

                          { grade letter to use in news batch job UUCP filenames }
                          NewsGrade            : CHAR;

                          { FALSE = Do not detect multitasker }
                          TimeSlicing          : BOOLEAN;

                          { TRUE = scan and decode files from imported netmail }
                          NetmailDecode        : BOOLEAN;

                          { where to store the files }
                          NetmailDecodePath    : STRING[79];

                          { TRUE = scan and decode files from imported private scanned messages }
                          PrivateDecode        : BOOLEAN;

                          { where to store the files }
                          PrivateDecodePath    : STRING[79];

                          { maximum length for rmail line in .X file }
                          MaxRMailLineLen      : WORD;

                          { minimum megabytes free for disk check }
                          MinimumDiskFree      : BYTE; { mb }

                          { drives to check for disk check }
                          DiskFreeDrives       : STRING[26];

                          OLD                  : BYTE;

                          { rmail correction to use }
                          RMailCorrect         : BYTE;

                          { TRUE = gate Message-ID -> MSGID }
                          GateMsgId            : BOOLEAN;

                          { TRUE = don't put "0" in front of UUCP jobs }
                          ForceNoBitmask       : BOOLEAN;

                          { editor rescan flag file }
                          RescanFlagFile2      : STRING[79];

                          { Gate organization -> origin: no, yes, override }
                          OrganizationInOrigin : BYTE; { tri-state }

                          { TRUE = always use quoted-printable }
                          AlwaysMimeQuotePrint : BOOLEAN;

                          { address for dumping mail at ISP }
                          SmtpForward          : STRING[50];

                          { cross-post limit. 255 = allow all }
                          MaxXPostNewsgroups   : BYTE;

                          { path to MSGLOCK directory for WildCat conference lock }
                          WildCatMsgLockDir    : STRING[79];

                          { TRUE = create *.MSG with Opus date fields }
                          OpusDateFormat       : BOOLEAN;

                          { maximum length of a single WildCat message }
                          MaxWildCatMsgLen     : LONGINT;

                          { kill *.MSG with areafix after processing? }
                          KillAreaFixMsgs      : BOOLEAN;

                          { color codes for each of the elements }
                          Colors               : ARRAY[1..21] OF BYTE;
                    END;

{==========================================================================}
{                  LIST SERVER DATABASE                                    }
{==========================================================================}

{ The list server database holds the configuration of all the mailing }
{ lists and the connected users. There can be 65534 records.          }

TYPE ListServerRecord = RECORD
                              { TRUE of this record is deleted }
                              Deleted        : BOOLEAN;

                              { the type of information stored in this record }
                              { 0=Mailing list configuration                  }
                              { 1=Fido style subscription                     }
                              { 2=UUCP style subscription                     }
                              ListSystem     : BYTE;

                              { points to the next record with information }
                              { about a subscribed user. Points to first   }
                              { subscribed user in Mailing list record.    }
                              NextUser       : WORD;

                              { Access type for this user. 0=ReadWrite,    }
                              { 1=ReadOnly, 3=WriteOnly.                   }
                              Access         : BYTE;

                              { when the record was added, in unix format }
                              SubscribedDate : LONGINT;

                              { when the user last confirmed subscription, }
                              { in unix format, 0 if never set.            }
                              ConfirmedDate  : LONGINT;

                              { when last re-confirmation request was sent }
                              { out.                                       }
                              ConfirmReqDate : LONGINT;

                              { 0=Never, 1=Ok, 2=Try1, 3=Try2, 4=Try3 }
                              ConfirmState   : BYTE;

                              { last confirm code issued }
                              ConfirmCode    : LONGINT;

                              CASE INTEGER OF
                                   { Mailing list configuration }

                                        { name of the list }
                                   0 : (ListName        : STRING[30];

                                        { description text of this list }
                                        ListDescription : STRING[40];

                                        { path to the welcome file }
                                        ListWelcome     : STRING[79];

                                        { system AKA to use for this list. }
                                        { This is an index from 1 to 10 in }
                                        { the configuration record.        }
                                        ListAKA         : BYTE;
                                        ListPrivate     : BOOLEAN;
                                        OnlyKnown       : BOOLEAN;
                                        Active          : BOOLEAN;

                                        { name of the connected area }
                                        AreaName        : STRING[60];

                                        { TRUE = copy list msgs to the area }
                                        EchoList        : BOOLEAN;

                                        { TRUE = copy area msgs to list }
                                        ListEcho        : BOOLEAN;

                                        { Access type to set when connecting }
                                        { a new user. See Access above.      }
                                        DefaultAccess   : BYTE;

                                        { which header to put the mailing }
                                        { list address in. 0=Nowhere,     }
                                        { 1=From, 2=ReplyTo, 3=Sender     }
                                        MLAddress       : BYTE;

                                        { interval in days between }
                                        {re-confirmation checks    }
                                        ConfirmInterval : BYTE
                                       );

                                   { Fido style subscription fields }

                                        { AKA of this user }
                                   1 : (Address   : FidoAddrType;
                                        { full name }
                                        Username  : STRING[50]
                                       );

                                   { Usenet style subscription fields }
                                        { e-mail address }
                                   2 : (EmailAddr : STRING[50]
                                       );

                                   { Remote Gateway style subscription fields }
                                        { gateway AKA }
                                   3 : (GWAddress : FidoAddrType;
                                        { gateway user name }
                                        GWUser    : STRING[50];
                                        { recipient e-mail address }
                                        GWEmail   : STRING[50]
                                       );
                        END;

{==== END OF FILE ==========================================================}

