#include <shared/typedefs.h>
#include <shared/mystdlib.h>
#include <shared/jblist.h>
#include <shared/node4d.h>

#include <ctconfig.h>

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include <dos/dos.h>
#include <dos/datetime.h>

#include <clib/dos_protos.h>

#define CATCOMP_NUMBERS
#include <ctshared/crashtick_strings.h>

uchar *getString(ulong msgid);

uchar cfgbuf[4000];

extern uchar *config_version;

short CorrectFlags(uchar *flags)
{
   ulong c;

   for(c=0;c<strlen(flags);c++)
   {
      flags[c]=toupper(flags[c]);

      if(flags[c]<'A' || flags[c]>'Z')
         return(FALSE);
   }

   return(TRUE);
}

short ReadConfig(uchar *filename,struct Config *cfg,short *seconderr,ulong *cfgline,uchar *cfgerr)
{
   struct jbFile *cfgfh;
   uchar buf2[200],cfgword[20];

   struct Aka           *tmpaka,      *LastAka=NULL;
   struct ConfigNode    *tmpnode,     *LastCNode=NULL;
   struct Area          *tmparea,     *LastArea=NULL;
   struct Announce      *tmpannounce, *LastAnnounce=NULL;

   struct TickNode   *tmptnode;
   struct Node4D     tmp4d;

   cfg->configchanged=FALSE;

   *cfgline=0;

   if(!(cfgfh=jbOpen(filename,MODE_OLDFILE,5000)))
   {
      *seconderr=READCONFIG_NOT_FOUND;
      return(FALSE);
   }

   *seconderr=READCONFIG_INVALID;

   while(jbFGets(cfgfh,cfgbuf,4000))
   {
      jbcpos=0;
      (*cfgline)++;

      jbstrcpy(cfgword,cfgbuf,20);

      if(stricmp(cfgword,"AKA")==0)
      {
         if(!(tmpaka=(struct Aka *)AllocCleared(sizeof(struct Aka))))
         {
            *seconderr=READCONFIG_NO_MEM;
            jbClose(cfgfh);
            return(FALSE);
         }

         jbAddNode(&cfg->AkaList,(struct jbNode *)tmpaka);
         LastAka=tmpaka;

         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(Parse4D(buf2,&LastAka->Node)))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_NODE),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"GROUPNAME")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,2)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!CorrectFlags(buf2))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPNAME),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(cfg->cfg_GroupNames[buf2[0]-'A'],cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"NODE")==0)
      {
         if(!(tmpnode=(struct ConfigNode *)AllocCleared(sizeof(struct ConfigNode))))
         {
            *seconderr=READCONFIG_NO_MEM;
            jbClose(cfgfh);
            return(FALSE);
         }

         jbAddNode(&cfg->CNodeList,(struct jbNode *)tmpnode);
         LastCNode=tmpnode;

         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(Parse4D(buf2,&LastCNode->Node)))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_NODE));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastCNode->TickPW,cfgbuf,19)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         while(jbstrcpy(buf2,cfgbuf,200))
         {
            if(stricmp(buf2,"SENDHOLD")==0)
               LastCNode->Pri=PRI_HOLD;

            else if(stricmp(buf2,"SENDCRASH")==0)
               LastCNode->Pri=PRI_CRASH;

            else if(stricmp(buf2,"SENDDIRECT")==0)
               LastCNode->Pri=PRI_DIRECT;

            else if(stricmp(buf2,"PACKZIP")==0)
               LastCNode->Packer=PACKER_ZIP;

            else if(stricmp(buf2,"PACKALL")==0)
               LastCNode->Packmode=PACKMODE_PACKALL;

            else if(stricmp(buf2,"PACKTIC")==0)
               LastCNode->Packmode=PACKMODE_PACKTIC;

            else if(stricmp(buf2,"PACKLHA")==0)
               LastCNode->Packer=PACKER_LHA;

            else if(stricmp(buf2,"NOTIFY")==0)
               LastCNode->Flags|=NODE_NOTIFY;

            else if(stricmp(buf2,"PASSIVE")==0)
               LastCNode->Flags|=NODE_PASSIVE;

            else if(stricmp(buf2,"AUTOADD")==0)
               LastCNode->Flags|=NODE_AUTOADD;

            else if(stricmp(buf2,"TINYSEENBY")==0)
               LastCNode->Flags|=NODE_TINYSEENBY;

            else if(stricmp(buf2,"NOTICFILES")==0)
               LastCNode->Flags|=NODE_NOTICFILES;

            else
            {
               sprintf(cfgerr,getString(CFG_ERR_UNKNOWN_SWITCH),buf2);
               jbClose(cfgfh);
               return(FALSE);
            }
         }
      }
      else if(stricmp(cfgword,"RAIDINFO")==0)
      {
         if(!LastCNode)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"RAIDINFO","NODE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastCNode->RaidPW,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastCNode->FullAccessGroups,cfgbuf,30)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastCNode->ReadOnlyGroups,cfgbuf,30)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         jbstrcpy(LastCNode->WriteOnlyGroups,cfgbuf,30);

         if(!CorrectFlags(LastCNode->FullAccessGroups))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPS),LastCNode->FullAccessGroups);
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!CorrectFlags(LastCNode->ReadOnlyGroups))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPS),LastCNode->ReadOnlyGroups);
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!CorrectFlags(LastCNode->WriteOnlyGroups))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPS),LastCNode->ReadOnlyGroups);
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"DEFAULTGROUP")==0)
      {
         if(!LastCNode)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"DEFAULTGROUP","NODE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(buf2,cfgbuf,2)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!CorrectFlags(buf2))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPNAME),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         LastCNode->DefaultGroup=buf2[0];
      }
      else if(stricmp(cfgword,"REMOTESYSOP")==0)
      {
         if(!LastCNode)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"REMOTESYSOP","NODE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastCNode->SysopName,cfgbuf,36)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"AREA")==0)
      {
         if(!(tmparea=(struct Area *)AllocCleared(sizeof(struct Area))))
         {
            *seconderr=READCONFIG_NO_MEM;
            jbClose(cfgfh);
            return(FALSE);
         }

         jbNewList(&tmparea->TickNodes);
         jbAddNode(&cfg->AreaList,(struct jbNode *)tmparea);
         LastArea=tmparea;

         if(!(jbstrcpy(LastArea->Name,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(Parse4D(buf2,&tmp4d)))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_NODE),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         for(tmpaka=(struct Aka *)cfg->AkaList.First;tmpaka;tmpaka=tmpaka->Next)
            if(Compare4D(&tmp4d,&tmpaka->Node)==0) break;

         if(!tmpaka)
         {
            sprintf(cfgerr,getString(CFG_ERR_UNKNOWN_AKA),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Aka=tmpaka;
         jbstrcpy(LastArea->Directory,cfgbuf,80);
      }
      else if(stricmp(cfgword,"UNCONFIRMED")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"UNCONFIRMED","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Flags|=AREA_UNCONFIRMED;
      }
      else if(stricmp(cfgword,"MANDATORY")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"MANDATORY","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Flags|=AREA_MANDATORY;
      }
      else if(stricmp(cfgword,"DEFREADONLY")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"DEFREADONLY","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Flags|=AREA_DEFREADONLY;
      }
      else if(stricmp(cfgword,"NOREPLACE")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"NOREPLACE","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Flags|=AREA_NOREPLACE;
      }
      else if(stricmp(cfgword,"IGNORESEENBY")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"IGNORESEENBY","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Flags|=AREA_IGNORESEENBY;
      }
      else if(stricmp(cfgword,"EXPORT")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"EXPORT","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         while(jbstrcpy(buf2,cfgbuf,100))
         {
            uword flags;
            flags=0;

            if(buf2[0]=='!')
            {
               flags=TICKNODE_READONLY;
               strcpy(buf2,&buf2[1]);
            }

            if(buf2[0]=='@')
            {
               flags=TICKNODE_WRITEONLY;
               strcpy(buf2,&buf2[1]);
            }

            if(!(Parse4D(buf2,&tmp4d)))
            {
               sprintf(cfgerr,getString(CFG_ERR_INVALID_NODE),buf2);
               jbClose(cfgfh);
               return(FALSE);
            }

            for(tmpnode=(struct ConfigNode *)cfg->CNodeList.First;tmpnode;tmpnode=tmpnode->Next)
               if(Compare4D(&tmp4d,&tmpnode->Node)==0) break;

            if(!tmpnode)
            {
               sprintf(cfgerr,getString(CFG_ERR_UNCONFIGURED_NODE),buf2);
               jbClose(cfgfh);
               return(FALSE);
            }

            if(!(tmptnode=(struct TickNode *)AllocCleared(sizeof(struct TickNode))))
            {
               *seconderr=READCONFIG_NO_MEM;
               jbClose(cfgfh);
               return(FALSE);
            }

            jbAddNode(&LastArea->TickNodes,(struct jbNode *)tmptnode);
            tmptnode->ConfigNode=tmpnode;
            tmptnode->Flags=flags;
         }
      }
      else if(stricmp(cfgword,"DESCRIPTION")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"DESCRIPTION","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastArea->Description,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"USERDATA")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"USERDATA","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastArea->UserData,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"AREACOMMAND")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"AREACOMMAND","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastArea->AreaCommand,cfgbuf,100)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"GROUP")==0)
      {
         if(!LastArea)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"GROUP","AREA");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(buf2,cfgbuf,30)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!CorrectFlags(buf2))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPNAME),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         LastArea->Group=buf2[0];
      }
      else if(stricmp(cfgword,"ANNOUNCE")==0 || stricmp(cfgword,"ANNOUNCEFILE")==0)
      {
         if(!(tmpannounce=(struct Announce *)AllocCleared(sizeof(struct Announce))))
         {
            *seconderr=READCONFIG_NO_MEM;
            jbClose(cfgfh);
            return(FALSE);
         }

         jbNewList(&tmpannounce->LineList);
         jbAddNode(&cfg->AnnounceList,(struct jbNode *)tmpannounce);
         LastAnnounce=tmpannounce;

         tmpannounce->Method=ANNOUNCE_PKT;

         if(stricmp(cfgword,"ANNOUNCEFILE")==0)
            tmpannounce->Method=ANNOUNCE_FILE;

         if(!(jbstrcpy(LastAnnounce->Groups,cfgbuf,30)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!CorrectFlags(LastAnnounce->Groups))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_GROUPS),LastAnnounce->Groups);
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->Name,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(Parse4D(buf2,&tmp4d)))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_NODE),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         for(tmpaka=(struct Aka *)cfg->AkaList.First;tmpaka;tmpaka=tmpaka->Next)
            if(Compare4D(&tmp4d,&tmpaka->Node)==0) break;

         if(!tmpaka)
         {
            sprintf(cfgerr,getString(CFG_ERR_UNKNOWN_AKA),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }

         LastAnnounce->Aka=tmpaka;
      }
      else if(stricmp(cfgword,"HEADER")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"HEADER","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->Header,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"FOOTER")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"FOOTER","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->Footer,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"FORMAT")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"FORMAT","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->Format,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"AREAHEADER")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"AREAHEADER","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->AreaHeader,cfgbuf,500)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"AREAFOOTER")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"AREAFOOTER","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->AreaFooter,cfgbuf,500)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"ORIGIN")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"ORIGIN","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->Origin,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"SUBJECT")==0)
      {
         if(!LastAnnounce)
         {
            sprintf(cfgerr,getString(CFG_ERR_XXX_BEFORE_XXX),"SUBJECT","ANNOUNCE");
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(jbstrcpy(LastAnnounce->Subject,cfgbuf,72)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"INBOUND")==0)
      {
         if(!(jbstrcpy(cfg->cfg_Inbound,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"OUTBOUND")==0)
      {
         if(!(jbstrcpy(cfg->cfg_Outbound,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"TICKDIR")==0)
      {
         if(!(jbstrcpy(cfg->cfg_Tickdir,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"FILEBASE")==0)
      {
         if(!(jbstrcpy(cfg->cfg_Filebase,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"BADTICK")==0)
      {
         if(!(jbstrcpy(cfg->cfg_BadTick,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"AUTOADDDIR")==0)
      {
         if(!(jbstrcpy(cfg->cfg_AutoAddDir,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"SYSOP")==0)
      {
         if(!(jbstrcpy(cfg->cfg_Sysop,cfgbuf,35)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"RAIDHELP")==0)
      {
         if(!(jbstrcpy(cfg->cfg_RaidHelp,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"LOGFILE")==0)
      {
         if(!(jbstrcpy(cfg->cfg_Logfile,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"LOGLEVEL")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,100)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(atoi(buf2)<1 || atoi(buf2)>6)
         {
            sprintf(cfgerr,getString(CFG_ERR_LEVEL_OUT_OF_RANGE));
            jbClose(cfgfh);
            return(FALSE);
         }

         cfg->cfg_Loglevel=atoi(buf2);
      }
      else if(stricmp(cfgword,"LOGBUFFERLINES")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,100)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         cfg->cfg_LogBufferLines=atoi(buf2);
      }
      else if(stricmp(cfgword,"LOGBUFFERSECS")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,100)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         cfg->cfg_LogBufferSecs=atoi(buf2);
      }
      else if(stricmp(cfgword,"STATSFILE")==0)
      {
         if(!(jbstrcpy(cfg->cfg_StatsFile,cfgbuf,40)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"IMPORTCOMMAND")==0)
      {
         if(!(jbstrcpy(cfg->cfg_ImportCommand,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"MAGICCOMMAND")==0)
      {
         if(!(jbstrcpy(cfg->cfg_MagicCommand,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"REPLACECOMMAND")==0)
      {
         if(!(jbstrcpy(cfg->cfg_ReplaceCommand,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"ZIPEXTRACT")==0)
      {
         if(!(jbstrcpy(cfg->cfg_ZipExtract,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"ZIPADD")==0)
      {
         if(!(jbstrcpy(cfg->cfg_ZipAdd,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"LHAEXTRACT")==0)
      {
         if(!(jbstrcpy(cfg->cfg_LhaExtract,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"LHAADD")==0)
      {
         if(!(jbstrcpy(cfg->cfg_LhaAdd,cfgbuf,80)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"FAKENODE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         if(!(Parse4D(buf2,&cfg->cfg_Fake4D)))
         {
            sprintf(cfgerr,getString(CFG_ERR_INVALID_NODE),buf2);
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"FAKEPASSWORD")==0)
      {
         if(!(jbstrcpy(cfg->cfg_FakePW,cfgbuf,9)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }
      }
      else if(stricmp(cfgword,"UNATTENDED")==0)
      {
         cfg->cfg_Flags|=CFG_UNATTENDED;
      }
      else if(stricmp(cfgword,"FILENOTE")==0)
      {
         cfg->cfg_Flags|=CFG_FILENOTE;
      }
      else if(stricmp(cfgword,"CHECKCRC")==0)
      {
         cfg->cfg_Flags|=CFG_CHECKCRC;
      }
      else if(stricmp(cfgword,"ALLOWREPLACE")==0)
      {
         cfg->cfg_Flags|=CFG_ALLOWREPLACE;
      }
      else if(stricmp(cfgword,"CHECKSEENBY")==0)
      {
         cfg->cfg_Flags|=CFG_CHECKSEENBY;
      }
      else if(stricmp(cfgword,"USEFILEBASE")==0)
      {
         cfg->cfg_Flags|=CFG_USEFILEBASE;
      }
      else if(stricmp(cfgword,"MAXWAITPICKUP")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         cfg->cfg_MaxWaitPickup=atoi(buf2);
      }
      else if(stricmp(cfgword,"RAIDMAXLINES")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
         {
            sprintf(cfgerr,getString(CFG_ERR_MISSING_ARG));
            jbClose(cfgfh);
            return(FALSE);
         }

         cfg->cfg_RaidMaxLines=atoi(buf2);
      }
      else if(cfgbuf[0]!=10 && cfgbuf[0]!=0 && cfgbuf[0]!=';')
      {
         sprintf(cfgerr,getString(CFG_ERR_UNKNOWN_KEYWORD),cfgword);
         jbClose(cfgfh);
         return(FALSE);
      }
   }

   jbClose(cfgfh);

   strcpy(cfg->filename,filename);

   return(TRUE);
}

short WriteConfig(struct Config *cfg,uchar *cfgerr)
{
   uchar cfgtemp[100],cfgbak[100];
   BPTR cfgfh;
   struct DateTime dt;
   uchar date[40],time[40];
   uword c;

   struct Aka           *tmpaka;
   struct ConfigNode    *tmpnode;
   struct Area          *tmparea;
   struct Announce      *tmpannounce;

   struct TickNode   *tmptnode;

   strcpy(cfgtemp,cfg->filename);
   strcat(cfgtemp,".tmp");

   strcpy(cfgbak,cfg->filename);
   strcat(cfgbak,".bak");

   if(!(cfgfh=Open(cfgtemp,MODE_NEWFILE)))
   {
      sprintf(cfgerr,getString(CFG_ERR_FAILED_WRITE_CFG),cfgtemp);
      return(FALSE);
   }

   cfg->configchanged=FALSE;

   DateStamp(&dt.dat_Stamp);
   dt.dat_Format=FORMAT_DOS;
   dt.dat_Flags=0;
   dt.dat_StrDay=NULL;
   dt.dat_StrDate=date;
   dt.dat_StrTime=time;
   DateToStr(&dt);

   FPrintf(cfgfh,"; Generated by %s\n; %s %s\n",config_version,date,time);

   FPrintf(cfgfh,"\n; General\n\n");

   WriteString(cfgfh,"SYSOP",cfg->cfg_Sysop);

   FPrintf(cfgfh,"\n");
   WriteString(cfgfh,"IMPORTCOMMAND",cfg->cfg_ImportCommand);
   WriteString(cfgfh,"MAGICCOMMAND",cfg->cfg_MagicCommand);
   WriteString(cfgfh,"REPLACECOMMAND",cfg->cfg_ReplaceCommand);

   FPrintf(cfgfh,"\n");
   FPrintf(cfgfh,"FAKENODE ");
   WriteNode(cfgfh,&cfg->cfg_Fake4D);
   FPrintf(cfgfh,"\n");
   WriteString(cfgfh,"FAKEPASSWORD",cfg->cfg_FakePW);
   FPrintf(cfgfh,"\n");

   WriteString(cfgfh,"LOGFILE",cfg->cfg_Logfile);
   FPrintf(cfgfh,"LOGLEVEL %ld\n",cfg->cfg_Loglevel);
   FPrintf(cfgfh,"LOGBUFFERLINES %ld\n",cfg->cfg_LogBufferLines);
   FPrintf(cfgfh,"LOGBUFFERSECS %ld\n",cfg->cfg_LogBufferSecs);

   FPrintf(cfgfh,"\n");
   FPrintf(cfgfh,"MAXWAITPICKUP %ld\n",cfg->cfg_MaxWaitPickup);
   FPrintf(cfgfh,"RAIDMAXLINES %ld\n",cfg->cfg_RaidMaxLines);

   FPrintf(cfgfh,"\n; Options\n\n");

   WriteSwitch(cfgfh,"CHECKCRC",cfg->cfg_Flags & CFG_CHECKCRC);
   WriteSwitch(cfgfh,"ALLOWREPLACE",cfg->cfg_Flags & CFG_ALLOWREPLACE);
   WriteSwitch(cfgfh,"CHECKSEENBY",cfg->cfg_Flags & CFG_CHECKSEENBY);
   WriteSwitch(cfgfh,"USEFILEBASE",cfg->cfg_Flags & CFG_USEFILEBASE);
   WriteSwitch(cfgfh,"UNATTENDED",cfg->cfg_Flags & CFG_UNATTENDED);
   WriteSwitch(cfgfh,"FILENOTE",cfg->cfg_Flags & CFG_FILENOTE);

   FPrintf(cfgfh,"\n; Paths\n\n");

   WriteString(cfgfh,"INBOUND",cfg->cfg_Inbound);
   WriteString(cfgfh,"OUTBOUND",cfg->cfg_Outbound);
   WriteString(cfgfh,"TICKDIR",cfg->cfg_Tickdir);
   WriteString(cfgfh,"FILEBASE",cfg->cfg_Filebase);
   WriteString(cfgfh,"BADTICK",cfg->cfg_BadTick);
   WriteString(cfgfh,"AUTOADDDIR",cfg->cfg_AutoAddDir);
   WriteString(cfgfh,"STATSFILE",cfg->cfg_StatsFile);
   WriteString(cfgfh,"RAIDHELP",cfg->cfg_RaidHelp);

   FPrintf(cfgfh,"\n; Packers\n\n");

   WriteString(cfgfh,"ZIPEXTRACT",cfg->cfg_ZipExtract);
   WriteString(cfgfh,"ZIPADD",cfg->cfg_ZipAdd);
   WriteString(cfgfh,"LHAEXTRACT",cfg->cfg_LhaExtract);
   WriteString(cfgfh,"LHAADD",cfg->cfg_LhaAdd);

   FPrintf(cfgfh,"\n; Groupnames\n\n");

   for(c=0;c<26;c++)
   {
      if(cfg->cfg_GroupNames[c][0]!=0)
      {
         FPrintf(cfgfh,"GROUPNAME %lc ",'A'+c);
         SafeWrite(cfgfh,cfg->cfg_GroupNames[c]);
         FPrintf(cfgfh,"\n");
      }
   }

   FPrintf(cfgfh,"\n; Akas\n\n");

   for(tmpaka=(struct Aka *)cfg->AkaList.First;tmpaka;tmpaka=tmpaka->Next)
   {
      FPrintf(cfgfh,"AKA ");
      WriteNode(cfgfh,&tmpaka->Node);
      FPrintf(cfgfh,"\n");
   }

   FPrintf(cfgfh,"\n; Nodes\n\n");

   for(tmpnode=(struct ConfigNode *)cfg->CNodeList.First;tmpnode;tmpnode=tmpnode->Next)
   {
      FPrintf(cfgfh,"NODE ");
      WriteNode(cfgfh,&tmpnode->Node);
      FPrintf(cfgfh," ");
      SafeWrite(cfgfh,tmpnode->TickPW);

      if(tmpnode->Pri == PRI_HOLD)
         FPrintf(cfgfh," SENDHOLD");

      if(tmpnode->Pri == PRI_CRASH)
         FPrintf(cfgfh," SENDCRASH");

      if(tmpnode->Pri == PRI_DIRECT)
         FPrintf(cfgfh," SENDDIRECT");

      if(tmpnode->Packer == PACKER_LHA)
         FPrintf(cfgfh," PACKLHA");

      if(tmpnode->Packer == PACKER_ZIP)
         FPrintf(cfgfh," PACKZIP");

      if(tmpnode->Packmode == PACKMODE_PACKALL)
         FPrintf(cfgfh," PACKALL");

      if(tmpnode->Packmode == PACKMODE_PACKTIC)
         FPrintf(cfgfh," PACKTIC");

      if(tmpnode->Flags & NODE_NOTIFY)
         FPrintf(cfgfh," NOTIFY");

      if(tmpnode->Flags & NODE_PASSIVE)
         FPrintf(cfgfh," PASSIVE");

      if(tmpnode->Flags & NODE_AUTOADD)
         FPrintf(cfgfh," AUTOADD");

      if(tmpnode->Flags & NODE_TINYSEENBY)
         FPrintf(cfgfh," TINYSEENBY");

      if(tmpnode->Flags & NODE_NOTICFILES)
         FPrintf(cfgfh," NOTICFILES");

      FPrintf(cfgfh,"\n");

      if(tmpnode->RaidPW[0] || tmpnode->FullAccessGroups[0] || tmpnode->ReadOnlyGroups[0] || tmpnode->WriteOnlyGroups[0])
      {
         FPrintf(cfgfh,"RAIDINFO ");
         SafeWrite(cfgfh,tmpnode->RaidPW);
         FPrintf(cfgfh," ");
         SafeWrite(cfgfh,tmpnode->FullAccessGroups);
         FPrintf(cfgfh," ");
         SafeWrite(cfgfh,tmpnode->ReadOnlyGroups);
         FPrintf(cfgfh," ");
         SafeWrite(cfgfh,tmpnode->WriteOnlyGroups);
         FPrintf(cfgfh,"\n");
      }

      if(tmpnode->DefaultGroup)
         FPrintf(cfgfh,"DEFAULTGROUP %lc\n",tmpnode->DefaultGroup);

      if(tmpnode->SysopName[0])
         WriteString(cfgfh,"REMOTESYSOP",tmpnode->SysopName);

      FPrintf(cfgfh,"\n");
   }

   FPrintf(cfgfh,"\n; Announce\n\n");

   for(tmpannounce=(struct Announce *)cfg->AnnounceList.First;tmpannounce;tmpannounce=tmpannounce->Next)
   {
      if(tmpannounce->Method == ANNOUNCE_FILE)
         FPrintf(cfgfh,"ANNOUNCEFILE ");

      else
         FPrintf(cfgfh,"ANNOUNCE ");

      SafeWrite(cfgfh,tmpannounce->Groups);
      FPrintf(cfgfh," ");
      SafeWrite(cfgfh,tmpannounce->Name);
      FPrintf(cfgfh," ");
      WriteNode(cfgfh,&tmpannounce->Aka->Node);
      FPrintf(cfgfh,"\n");

      if(tmpannounce->Origin[0])
         WriteString(cfgfh,"ORIGIN",tmpannounce->Origin);

      if(tmpannounce->Subject[0])
         WriteString(cfgfh,"SUBJECT",tmpannounce->Subject);

      if(tmpannounce->Format[0])
         WriteString(cfgfh,"FORMAT",tmpannounce->Format);

      if(tmpannounce->AreaFooter[0])
         WriteString(cfgfh,"AREAFOOTER",tmpannounce->AreaFooter);

      if(tmpannounce->AreaHeader[0])
         WriteString(cfgfh,"AREAHEADER",tmpannounce->AreaHeader);

      if(tmpannounce->Header[0])
         WriteString(cfgfh,"HEADER",tmpannounce->Header);

      if(tmpannounce->Footer[0])
         WriteString(cfgfh,"FOOTER",tmpannounce->Footer);

      FPrintf(cfgfh,"\n");
   }

   FPrintf(cfgfh,"\n; Areas\n\n");

   for(tmparea=(struct Area *)cfg->AreaList.First;tmparea;tmparea=tmparea->Next)
   {
      FPrintf(cfgfh,"AREA ");
      SafeWrite(cfgfh,tmparea->Name);
      FPrintf(cfgfh," ");
      WriteNode(cfgfh,&tmparea->Aka->Node);
      FPrintf(cfgfh," ");

      if(tmparea->Directory[0])
         SafeWrite(cfgfh,tmparea->Directory);

      FPrintf(cfgfh,"\n");

      if(tmparea->Flags & AREA_UNCONFIRMED)
         FPrintf(cfgfh,"UNCONFIRMED\n");

      if(tmparea->Flags & AREA_MANDATORY)
         FPrintf(cfgfh,"MANDATORY\n");

      if(tmparea->Flags & AREA_DEFREADONLY)
         FPrintf(cfgfh,"DEFREADONLY\n");

      if(tmparea->Flags & AREA_NOREPLACE)
         FPrintf(cfgfh,"NOREPLACE\n");

      if(tmparea->Flags & AREA_IGNORESEENBY)
         FPrintf(cfgfh,"IGNORESEENBY\n");

      if(tmparea->Description[0])
         WriteString(cfgfh,"DESCRIPTION",tmparea->Description);

      if(tmparea->UserData[0])
         WriteString(cfgfh,"USERDATA",tmparea->UserData);

      if(tmparea->AreaCommand[0])
         WriteString(cfgfh,"AREACOMMAND",tmparea->AreaCommand);

      if(tmparea->Group)
         FPrintf(cfgfh,"GROUP %lc\n",tmparea->Group);

      c=0;

      for(tmptnode=(struct TickNode *)tmparea->TickNodes.First;tmptnode;tmptnode=tmptnode->Next)
      {
         if(c%10==0)
         {
            if(c!=0) FPrintf(cfgfh,"\n");
            FPrintf(cfgfh,"EXPORT");
         }

         FPrintf(cfgfh," ");

         if(tmptnode->Flags & TICKNODE_READONLY)
            FPrintf(cfgfh,"!");

         if(tmptnode->Flags & TICKNODE_WRITEONLY)
            FPrintf(cfgfh,"@");

         WriteNode(cfgfh,&tmptnode->ConfigNode->Node);
         c++;
      }

      if(c!=0)
         FPrintf(cfgfh,"\n");

      FPrintf(cfgfh,"\n");
   }

   Close(cfgfh);

   DeleteFile(cfgbak);
   Rename(cfg->filename,cfgbak);
   Rename(cfgtemp,cfg->filename);

   return(TRUE);
}

void WriteString(BPTR fh,uchar *name,uchar *str)
{
   FPrintf(fh,"%s ",name);
   SafeWrite(fh,str);
   FPrintf(fh,"\n");
}

void WriteSwitch(BPTR fh,uchar *name,ulong set)
{
   if(set)
      FPrintf(fh,"%s\n",name);

   else
      FPrintf(fh,";%s\n",name);
}

void WriteNode(BPTR fh,struct Node4D *n4d)
{
   FPrintf(fh,"%lu:%lu/%lu.%lu",n4d->Zone,n4d->Net,n4d->Node,n4d->Point);
}

void SafeWrite(BPTR fh,uchar *str)
{
   uchar buf[300];
   uword c,d;

   d=0;

   for(c=0;str[c];c++)
   {
      if(str[c]=='"' || str[c]=='\\')
         buf[d++]='\\';

      buf[d++]=str[c];
   }

   buf[d]=0;

   FPrintf(fh,"\"%s\"",buf);
}


void InitConfig(struct Config *cfg)
{
   short c;

   cfg->configchanged=FALSE;
   cfg->filename[0]=0;

   strcpy(cfg->cfg_Sysop,"Sysop");

   cfg->cfg_Inbound[0]=0;
   cfg->cfg_Outbound[0]=0;
   cfg->cfg_Tickdir[0]=0;
   cfg->cfg_Filebase[0]=0;
   cfg->cfg_BadTick[0]=0;
   cfg->cfg_AutoAddDir[0]=0;

   cfg->cfg_Fake4D.Zone=0;
   cfg->cfg_Fake4D.Net=0;
   cfg->cfg_Fake4D.Node=0;
   cfg->cfg_Fake4D.Point=0;
   cfg->cfg_FakePW[0]=0;
   
   cfg->cfg_Loglevel=5;
   cfg->cfg_LogBufferLines=10;
   cfg->cfg_LogBufferSecs=3;

   strcpy(cfg->cfg_Logfile,"PROGDIR:CrashTick.log");
   strcpy(cfg->cfg_StatsFile,"PROGDIR:CrashTick.stats");

   cfg->cfg_ImportCommand[0]=0;
   cfg->cfg_ReplaceCommand[0]=0;

   strcpy(cfg->cfg_LhaExtract,"lha x %a");
   strcpy(cfg->cfg_LhaAdd,"lha a %a %f");

   strcpy(cfg->cfg_ZipExtract,"unzip %a");
   strcpy(cfg->cfg_ZipAdd,"zip %a %f");

   cfg->cfg_RaidHelp[0]=0;

   cfg->cfg_Flags = 0;
   cfg->cfg_MaxWaitPickup=0;
   cfg->cfg_RaidMaxLines=0;

   for(c=0;c<30;c++)
      cfg->cfg_GroupNames[c][0]=0;

   jbNewList(&cfg->AkaList);
   jbNewList(&cfg->AreaList);
   jbNewList(&cfg->CNodeList);
   jbNewList(&cfg->AnnounceList);
}

void FreeConfig(struct Config *cfg)
{
   struct Area *area;
   
   for(area=(struct Area *)cfg->AreaList.First;area;area=area->Next)
      jbFreeList(&area->TickNodes,sizeof(struct TickNode));

   jbFreeList(&cfg->AkaList,sizeof(struct Aka));
   jbFreeList(&cfg->AreaList,sizeof(struct Area));
   jbFreeList(&cfg->CNodeList,sizeof(struct ConfigNode));
   jbFreeList(&cfg->AnnounceList,sizeof(struct Announce));
}

short CheckConfig(struct Config *cfg,uchar *charerr)
{
   struct Area *area;

   if(cfg->cfg_Filebase[0] == 0)
   {
      for(area=(struct Area *)cfg->AreaList.First;area;area=area->Next)
         if(area->Directory[0] == 0)
         {
            sprintf(charerr,getString(CFG_ERR_NO_DIR_AND_NO_FILEBASE),area->Name);
            return(FALSE);
         }
   }

   if((cfg->cfg_Flags & CFG_USEFILEBASE) && cfg->cfg_Filebase[0] == 0)
   {
      sprintf(charerr,getString(CFG_ERR_USEFILEBASE_AND_NO_FILEBASE),area->Name);
      return(FALSE);
   }

   if(!cfg->AkaList.First)
   {
      sprintf(charerr,getString(CFG_ERR_NO_AKAS),area->Name);
      return(FALSE);
   }

   return TRUE;
}

