#include <stdarg.h>
#include <varargs.h>
#include <stdio.h>

#include <strings.h>
#include <stdlib.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>

#include <cmshared/jblist.h>
#include <cmshared/jbio.h>
#include <cmshared/config.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>

ConfigNoMem(void);
ConfigError(UBYTE *str,...);

BOOL Parse4D(UBYTE *buf, struct Node4D *node);
int Compare4D(struct Node4D *node1,struct Node4D *node2);
BOOL Parse4DPat(UBYTE *buf, struct Node4DPat *node);
BOOL Parse4DDestPat(UBYTE *buf, struct Node4DPat *node);
BOOL Parse2DPat(UBYTE *buf, struct Node2DPat *node);
int Compare4DPat(struct Node4DPat *nodepat,struct Node4D *node);
int Compare2DPat(struct Node2DPat *nodepat,UWORD net,UWORD node);
void Copy4D(struct Node4D *node1,struct Node4D *node2);
void Print4DPat(struct Node4DPat *pat,UBYTE *dest);
void Print4DDestPat(struct Node4DPat *pat,UBYTE *dest);

BOOL CorrectFlags(UBYTE *flags);

UBYTE cfg_Sysop[40];
UBYTE cfg_Inbound[40];
UBYTE cfg_Outbound[40];
UBYTE cfg_TempDir[40];
UBYTE cfg_PacketCreate[40];
UBYTE cfg_PacketDir[40];
UBYTE cfg_LogFile[40];
UBYTE cfg_StatsFile[40];
ULONG cfg_LogLevel;
UBYTE cfg_DupeFile[40];
ULONG cfg_DupeSize;
ULONG cfg_MaxPktSize;
ULONG cfg_MaxBundleSize;
UBYTE cfg_DefaultOrigin[80];
UBYTE cfg_NodeList[40];
UWORD cfg_NodeListType;
UBYTE cfg_AreaFixHelp[40];
UBYTE cfg_GatewayName[40];
struct Node4D cfg_GatewayNode;
UBYTE *cfg_LocalCharset;

ULONG cfg_AreaFixMaxLines;

ULONG cfg_LogBufferSecs;
ULONG cfg_LogBufferLines;

UBYTE cfg_UMSName[80];
UBYTE cfg_UMSPassword[80];
UBYTE cfg_UMSServer[80];
UBYTE cfg_UMSGatewayName[36];

ULONG cfg_Flags;
ULONG cfg_Flags2;
UWORD cfg_DupeMode;
UWORD cfg_LoopMode;
ULONG cfg_DefaultZone;

struct jbList AkaList;
struct jbList AreaList;
struct jbList CNodeList;
struct jbList PackerList;
struct jbList RouteList;
struct jbList FileAttachList;
struct jbList BounceList;
struct jbList ChangeList;
struct jbList RemapList;
struct jbList RemapNodeList;
struct jbList RobotList;
struct jbList CharsetList;
struct jbList AreaFixList;
struct jbList ArealistList;

UBYTE cfg_GroupNames[30][80];

struct jbFile *cfgfh;
ULONG cfgline=0;
UBYTE cfgbuf[4000];

extern UBYTE *config_version;

BOOL jbstrcpy(UBYTE *dest,UBYTE *src,ULONG maxlen);
extern ULONG jbcpos;

BOOL ReadConfig(UBYTE *cfg,BPTR lockfh)
{
   UBYTE buf2[200],cfgword[30];
   ULONG c,d;

   struct Aka           *tmpaka,    *LastAka=NULL;
   struct ConfigNode    *tmpnode,   *LastCNode=NULL;
   struct Area          *tmparea,   *LastArea=NULL;
   struct Packer        *tmppacker, *LastPacker=NULL;
   struct Route         *tmproute;
   struct ImportNode    *tmpinode;
   struct PatternNode   *tmppatternnode;
   struct Change        *tmpchange;
   struct Remap         *tmpremap;
   struct RemapNode     *tmpremapnode;
   struct Robot         *tmprobot;
   struct CharsetAlias  *tmpcharsetalias;
   struct AreaFixName   *tmpareafixname;
   struct Arealist      *tmparealist;

   struct AddNode    *tmpaddnode;
   struct RemNode    *tmpremnode;
   struct TossNode   *tmptnode;
   struct BannedNode *tmpbnode;
   struct Node4D     tmp4d;

   UWORD flags;

   saveconfig=FALSE;
   cfgline=0;
   
   cfgfh=jbOpen(cfg,MODE_OLDFILE,10000);
   
   if(lockfh)
      Close(lockfh);

   if(!cfgfh)
      return(FALSE);

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

      jbstrcpy(cfgword,cfgbuf,30);

      if(stricmp(cfgword,"AKA")==0)
      {
         if(!(tmpaka=(struct Aka *)AllocMem(sizeof(struct Aka),MEMF_CLEAR)))
            ConfigNoMem();

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

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4D(buf2,&LastAka->Node)))
            ConfigError("Invalid node number \"%s\"",buf2);

         jbNewList(&LastAka->AddList);
         jbNewList(&LastAka->RemList);
      }
      else if(stricmp(cfgword,"ADDNODE")==0)
      {
         if(!LastAka)
            ConfigError("No AKA line");

         while(jbstrcpy(buf2,cfgbuf,100))
         {
            if(!(tmpaddnode=(struct AddNode *)AllocMem(sizeof(struct AddNode),MEMF_CLEAR)))
               ConfigNoMem();

            jbAddNode(&LastAka->AddList,(struct jbNode *)tmpaddnode);

            if(!(Parse4D(buf2,&tmpaddnode->Node)))
               ConfigError("Invalid node number \"%s\"",buf2);
         }
      }
      else if(stricmp(cfgword,"REMNODE")==0)
      {
         if(!LastAka)
            ConfigError("No AKA line");

         while(jbstrcpy(buf2,cfgbuf,100))
         {
            if(!(tmpremnode=(struct AddNode *)AllocMem(sizeof(struct RemNode),MEMF_CLEAR)))
               ConfigNoMem();

            jbAddNode(&LastAka->RemList,(struct jbNode *)tmpremnode);

            if(!Parse2DPat(buf2,&tmpremnode->NodePat))
               ConfigError("Invalid node pattern \"%s\"",buf2);
         }
      }
      else if(stricmp(cfgword,"FAKENET")==0)
      {
         if(!LastAka)
            ConfigError("No AKA line");

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         LastAka->FakeNet=atoi(buf2);
      }
      else if(stricmp(cfgword,"DOMAIN")==0)
      {
         if(!LastAka)
            ConfigError("No AKA line");

         if(!(jbstrcpy(LastAka->Domain,cfgbuf,200)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"GROUPNAME")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,2)))
            ConfigError("Missing argument");

         if(!CorrectFlags(buf2))
            ConfigError("Invalid group \"%s\"",buf2);

         if(!(jbstrcpy(cfg_GroupNames[buf2[0]-'A'],cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"NODE")==0)
      {
         if(!(tmpnode=(struct ConfigNode *)AllocMem(sizeof(struct ConfigNode),MEMF_CLEAR)))
            ConfigNoMem();

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

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4D(buf2,&LastCNode->Node)))
            ConfigError("Invalid node number \"%s\"",buf2);

         if(!(jbstrcpy(buf2,cfgbuf,10)))
            ConfigError("Missing argument");

         tmppacker=NULL;

         if(buf2[0]!=0)
         {
            for(tmppacker=PackerList.First;tmppacker;tmppacker=tmppacker->Next)
               if(stricmp(buf2,tmppacker->Name)==0) break;

            if(!tmppacker)
               ConfigError("Unknown packer \"%s\"",buf2);
         }

         LastCNode->Packer=tmppacker;

         if(!(jbstrcpy(LastCNode->PacketPW,cfgbuf,9)))
            ConfigError("Missing argument");

         while(jbstrcpy(buf2,cfgbuf,200))
         {
            if(stricmp(buf2,"STONEAGE")==0)
               LastCNode->Flags|=NODE_STONEAGE;

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

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

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

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

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

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

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

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

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

            else
               ConfigError("Unknown switch \"%s\"",buf2);
         }
      }
      else if(stricmp(cfgword,"AREAFIXINFO")==0)
      {
         UBYTE groupbuf[70];

         if(!LastCNode)
            ConfigError("No NODE specified");

         if(!(jbstrcpy(LastCNode->AreafixPW,cfgbuf,40)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(groupbuf,cfgbuf,70)))
            ConfigError("Missing argument");

         if(!CorrectFlags(LastCNode->Groups))
            ConfigError("Invalid groups \"%s\"",LastCNode->Groups);

         for(c=0;groupbuf[c]!=0 && groupbuf[c]!='!';c++);

         if(groupbuf[c]=='!')
         {
            groupbuf[c]=0;
            strcpy(LastCNode->Groups,groupbuf);

            strcpy(groupbuf,&groupbuf[c+1]);

            for(c=0;groupbuf[c]!=0 && groupbuf[c]!='!';c++);

            if(groupbuf[c]=='!')
            {
               groupbuf[c]=0;
               strcpy(LastCNode->ReadOnlyGroups,groupbuf);
               strcpy(LastCNode->AddGroups,&groupbuf[c+1]);
            }
            else
            {
               strcpy(LastCNode->ReadOnlyGroups,groupbuf);
            }
         }
         else
         {
            strcpy(LastCNode->Groups,groupbuf);
         }
      }
      else if(stricmp(cfgword,"DEFAULTGROUP")==0)
      {
         if(!LastCNode)
            ConfigError("No NODE line");

         if(!(jbstrcpy(buf2,cfgbuf,2)))
            ConfigError("Missing argument");

         if(!CorrectFlags(buf2))
            ConfigError("Invalid group \"%s\"",buf2);

         LastCNode->DefaultGroup=buf2[0];
      }
      else if(stricmp(cfgword,"AREA")==0 || stricmp(cfgword,"NETMAIL")==0)
      {
         if(!(tmparea=(struct Area *)AllocMem(sizeof(struct Area),MEMF_CLEAR)))
            ConfigNoMem();

         jbNewList(&tmparea->TossNodes);
         jbNewList(&tmparea->BannedNodes);

         jbAddNode(&AreaList,(struct jbNode *)tmparea);
         LastArea=tmparea;

         if(!(jbstrcpy(LastArea->Tagname,cfgbuf,80)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4D(buf2,&tmp4d)))
            ConfigError("Invalid node number \"%s\"",buf2);

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

         if(!tmpaka)
            ConfigError("Unknown AKA \"%s\"",buf2);

         LastArea->Aka=tmpaka;

         if(jbstrcpy(buf2,cfgbuf,200))
         {
            if(stricmp(buf2,"UMS")==0)
            {
               LastArea->AreaType=AREATYPE_UMS;
            }
            else if(stricmp(buf2,"MSG")==0)
            {
               LastArea->AreaType=AREATYPE_MSG;
            }
            else if(stricmp(buf2,"P/T")==0)
            {
               LastArea->AreaType=0;
            }
            else
            {
               ConfigError("Unknown messagebase format \"%s\"",buf2);
            }

            if(!(jbstrcpy(LastArea->Path,cfgbuf,80)))
               ConfigError("Missing argument");

            /* Export CHRS */

            if(jbstrcpy(buf2,cfgbuf,200))
            {
               LastArea->ExportCHRS=NULL;

               if(stricmp(buf2,"IBMPC")==0)
                  LastArea->ExportCHRS=AmigaToIbm;

               else if(stricmp(buf2,"SWEDISH")==0)
                  LastArea->ExportCHRS=AmigaToSF7;

               else if(stricmp(buf2,"MAC")==0)
                  LastArea->ExportCHRS=AmigaToMac;

               else if(stricmp(buf2,"ASCII")==0)
                  LastArea->ExportCHRS=(UBYTE *)CHARSET_ASCII;

               else if(stricmp(buf2,"LATIN-1")!=0)
                  ConfigError("Unknown character set \"%s\"",buf2);
            }

            /* DefaultCHRS */

            if(jbstrcpy(buf2,cfgbuf,200))
            {
               LastArea->DefaultCHRS=NULL;

               if(stricmp(buf2,"IBMPC")==0)
                  LastArea->DefaultCHRS=IbmToAmiga;

               else if(stricmp(buf2,"SWEDISH")==0)
                  LastArea->DefaultCHRS=SF7ToAmiga;

               else if(stricmp(buf2,"DEFAULT")==0)
                  LastArea->DefaultCHRS=DefToAmiga;

               else if(stricmp(buf2,"MAC")==0)
                  LastArea->DefaultCHRS=MacToAmiga;

               else if(stricmp(buf2,"LATIN-1")!=0)
                  ConfigError("Unknown character set \"%s\"",buf2);
            }
         }
         if(stricmp(cfgword,"NETMAIL")==0)
         {
            if(LastArea->AreaType==0)
               ConfigError("Netmail area cannot be pass-through");

            LastArea->Flags|=AREA_NETMAIL;
         }
         else if(stricmp(LastArea->Tagname,"BAD")==0)
         {
            if(LastArea->Path[0]==0)
               ConfigError("Bad area cannot be pass-through");

            LastArea->Flags|=AREA_BAD;
         }
         else if(stricmp(LastArea->Tagname,"DEFAULT")==0 || strnicmp(LastArea->Tagname,"DEFAULT_",8)==0)
         {
            LastArea->Flags|=AREA_DEFAULT;
         }
      }
      else if(stricmp(cfgword,"UNCONFIRMED")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         LastArea->Flags|=AREA_UNCONFIRMED;
      }
      else if(stricmp(cfgword,"MANDATORY")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         LastArea->Flags|=AREA_MANDATORY;
      }
      else if(stricmp(cfgword,"DEFREADONLY")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         LastArea->Flags|=AREA_DEFREADONLY;
      }
      else if(stricmp(cfgword,"IGNOREDUPES")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         LastArea->Flags|=AREA_IGNOREDUPES;
      }
      else if(stricmp(cfgword,"IGNORESEENBY")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         LastArea->Flags|=AREA_IGNORESEENBY;
      }
      else if(stricmp(cfgword,"EXPORT")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

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

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

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

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

            if(!(Parse4D(buf2,&tmp4d)))
               ConfigError("Invalid node number \"%s\"",buf2);

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

            if(!tmpnode)
               ConfigError("Unconfigured node \"%s\"",buf2);

            if(!(tmptnode=(struct TossNode *)AllocMem(sizeof(struct TossNode),MEMF_CLEAR)))
               ConfigNoMem();

            jbAddNode(&LastArea->TossNodes,(struct jbNode *)tmptnode);
            tmptnode->ConfigNode=tmpnode;
            tmptnode->Flags=flags;
         }
      }
      else if(stricmp(cfgword,"IMPORT")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         if(!(LastArea->Flags & AREA_NETMAIL))
            ConfigError("Not a netmail area");

         while(jbstrcpy(buf2,cfgbuf,100))
         {
            if(!(tmpinode=(struct TossNode *)AllocMem(sizeof(struct ImportNode),MEMF_CLEAR)))
               ConfigNoMem();

            jbAddNode(&LastArea->TossNodes,(struct jbNode *)tmpinode);

            if(!(Parse4D(buf2,&tmpinode->Node)))
               ConfigError("Invalid node number \"%s\"",buf2);
         }
      }
      else if(stricmp(cfgword,"BANNED")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         while(jbstrcpy(buf2,cfgbuf,100))
         {
            if(!(Parse4D(buf2,&tmp4d)))
               ConfigError("Invalid node number \"%s\"",buf2);

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

            if(!tmpnode)
               ConfigError("Unconfigured node \"%s\"",buf2);

            if(!(tmpbnode=(struct BannedNode *)AllocMem(sizeof(struct BannedNode),MEMF_CLEAR)))
               ConfigNoMem();

            jbAddNode(&LastArea->BannedNodes,(struct jbNode *)tmpbnode);
            tmpbnode->ConfigNode=tmpnode;
         }
      }
      else if(stricmp(cfgword,"DESCRIPTION")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         if(!(jbstrcpy(LastArea->Description,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"GROUP")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         if(!(jbstrcpy(buf2,cfgbuf,30)))
            ConfigError("Missing argument");

         if(!CorrectFlags(buf2))
            ConfigError("Invalid group \"%s\"",buf2);

         LastArea->Group=buf2[0];
      }
      else if(stricmp(cfgword,"KEEPNUM")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         if(!(jbstrcpy(buf2,cfgbuf,30)))
            ConfigError("Missing argument");

         LastArea->KeepNum=atol(buf2);
      }
      else if(stricmp(cfgword,"KEEPDAYS")==0)
      {
         if(!LastArea)
            ConfigError("No AREA line");

         if(!(jbstrcpy(buf2,cfgbuf,30)))
            ConfigError("Missing argument");

         LastArea->KeepDays=atol(buf2);
      }
      else if(stricmp(cfgword,"AREAFIXNAME")==0)
      {
         if(!(tmpareafixname=(struct AreaFixName *)AllocMem(sizeof(struct AreaFixName),MEMF_ANY)))
            ConfigNoMem();

         jbAddNode(&AreaFixList,(struct jbNode *)tmpareafixname);

         if(!(jbstrcpy(tmpareafixname->Name,cfgbuf,36)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"CHARSETALIAS")==0)
      {
         if(!(tmpcharsetalias=(struct CharsetAlias *)AllocMem(sizeof(struct CharsetAlias),MEMF_ANY)))
            ConfigNoMem();

         jbAddNode(&CharsetList,(struct jbNode *)tmpcharsetalias);

         if(!(jbstrcpy(tmpcharsetalias->Name,cfgbuf,20)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         tmpcharsetalias->CHRS=NULL;

         if(stricmp(buf2,"IBMPC")==0)
            tmpcharsetalias->CHRS=IbmToAmiga;

         else if(stricmp(buf2,"SWEDISH")==0)
            tmpcharsetalias->CHRS=SF7ToAmiga;

         else if(stricmp(buf2,"MAC")==0)
            tmpcharsetalias->CHRS=MacToAmiga;

         else if(stricmp(buf2,"LATIN-1")!=0)
            ConfigError("Unknown charset \"%s\"",buf2);

         strcpy(tmpcharsetalias->AliasName,buf2);
      }
      else if(stricmp(cfgword,"LOCALCHRS")==0)
      {
         if(!jbstrcpy(buf2,cfgbuf,100))
            ConfigError("Missing argument");

         cfg_LocalCharset=NULL;

         if(stricmp(buf2,"IBMPC")==0)
            cfg_LocalCharset=IbmToAmiga;

         else if(stricmp(buf2,"SWEDISH")==0)
            cfg_LocalCharset=SF7ToAmiga;

         else if(stricmp(buf2,"MAC")==0)
            cfg_LocalCharset=MacToAmiga;

         else if(stricmp(buf2,"LATIN-1")!=0)
            ConfigError("Unknown charset \"%s\"",buf2);
      }
      else if(stricmp(cfgword,"FILEATTACH")==0)
      {
         while(jbstrcpy(buf2,cfgbuf,100))
         {
            if(!(tmppatternnode=(struct PatternNode *)AllocMem(sizeof(struct PatternNode),MEMF_CLEAR)))
               ConfigNoMem();

            if(!(Parse4DPat(buf2,&tmppatternnode->Pattern)))
               ConfigError("Invalid node pattern \"%s\"",buf2);

            jbAddNode(&FileAttachList,(struct jbNode *)tmppatternnode);
         }
      }
      else if(stricmp(cfgword,"BOUNCE")==0)
      {
         while(jbstrcpy(buf2,cfgbuf,100))
         {
            if(!(tmppatternnode=(struct PatternNode *)AllocMem(sizeof(struct PatternNode),MEMF_CLEAR)))
               ConfigNoMem();

            if(!(Parse4DPat(buf2,&tmppatternnode->Pattern)))
               ConfigError("Invalid node pattern \"%s\"",buf2);

            jbAddNode(&BounceList,(struct jbNode *)tmppatternnode);
         }
      }
      else if(stricmp(cfgword,"INBOUND")==0)
      {
         if(!(jbstrcpy(cfg_Inbound,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"OUTBOUND")==0)
      {
         if(!(jbstrcpy(cfg_Outbound,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"DEFAULTORIGIN")==0)
      {
         if(!(jbstrcpy(cfg_DefaultOrigin,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"SYSOP")==0)
      {
         if(!(jbstrcpy(cfg_Sysop,cfgbuf,35)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"NODELIST")==0)
      {
         if(!(jbstrcpy(cfg_NodeList,cfgbuf,40)))
            ConfigError("Missing argument");

         cfg_NodeListType=NODELIST_TRAPLIST;

         if(jbstrcpy(buf2,cfgbuf,40))
         {
            if(stricmp(buf2,"TRAPLIST")==0)
               cfg_NodeListType=NODELIST_TRAPLIST;

            else if(stricmp(buf2,"GOTCHA")==0)
               cfg_NodeListType=NODELIST_GOTCHA;

            else
               ConfigError("Unsupported nodelist type");
         }
      }
      else if(stricmp(cfgword,"AREAFIXHELP")==0)
      {
         if(!(jbstrcpy(cfg_AreaFixHelp,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"LOGFILE")==0)
      {
         if(!(jbstrcpy(cfg_LogFile,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"LOGLEVEL")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,100)))
            ConfigError("Missing argument");

         if(atoi(buf2)<1 || atoi(buf2)>6)
            ConfigError("Loglevel out of range");

         cfg_LogLevel=atoi(buf2);
      }
      else if(stricmp(cfgword,"LOGBUFFERLINES")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,100)))
            ConfigError("Missing argument");

         cfg_LogBufferLines=atoi(buf2);
      }
      else if(stricmp(cfgword,"LOGBUFFERSECS")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,100)))
            ConfigError("Missing argument");

         cfg_LogBufferSecs=atoi(buf2);
      }
      else if(stricmp(cfgword,"STATSFILE")==0)
      {
         if(!(jbstrcpy(cfg_StatsFile,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"DUPEFILE")==0)
      {
         if(!(jbstrcpy(cfg_DupeFile,cfgbuf,40)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         cfg_DupeSize=atoi(buf2)*1024;
      }
      else if(stricmp(cfgword,"DUPEMODE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(stricmp(buf2,"IGNORE")==0)
            cfg_DupeMode=DUPE_IGNORE;

         else if(stricmp(buf2,"KILL")==0)
            cfg_DupeMode=DUPE_KILL;

         else if(stricmp(buf2,"BAD")==0)
            cfg_DupeMode=DUPE_BAD;

         else
            ConfigError("Unknown dupemode \"%s\"",buf2);
      }
      else if(stricmp(cfgword,"LOOPMODE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(stricmp(buf2,"IGNORE")==0)
            cfg_LoopMode=LOOP_IGNORE;

         else if(stricmp(buf2,"LOG")==0)
            cfg_LoopMode=LOOP_LOG;

         else if(stricmp(buf2,"LOG+BAD")==0)
            cfg_LoopMode=LOOP_LOGBAD;

         else
            ConfigError("Unknown dupemode \"%s\"",buf2);
      }
      else if(stricmp(cfgword,"TEMPDIR")==0)
      {
         if(!(jbstrcpy(cfg_TempDir,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"CREATEPKTDIR")==0)
      {
         if(!(jbstrcpy(cfg_PacketCreate,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"PACKETDIR")==0)
      {
         if(!(jbstrcpy(cfg_PacketDir,cfgbuf,40)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"PACKER")==0)
      {
         if(!(tmppacker=(struct Packer *)AllocMem(sizeof(struct Packer),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&PackerList,(struct jbNode *)tmppacker);
         LastPacker=tmppacker;

         if(!(jbstrcpy(LastPacker->Name,cfgbuf,10)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(LastPacker->Packer,cfgbuf,80)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(LastPacker->Unpacker,cfgbuf,80)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(LastPacker->Recog,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"ROUTE")==0)
      {
         if(!(tmproute=(struct Route *)AllocMem(sizeof(struct Route),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&RouteList,(struct jbNode *)tmproute);

         /* Pattern */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4DPat(buf2,&tmproute->Pattern)))
            ConfigError("Invalid node pattern \"%s\"",buf2);

         /* Dest */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4DDestPat(buf2,&tmproute->DestPat)))
            ConfigError("Invalid node pattern \"%s\"",buf2);

         /* Aka */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4D(buf2,&tmp4d)))
            ConfigError("Invalid node number \"%s\"",buf2);

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

         if(!tmpaka)
            ConfigError("Unconfigured aka \"%s\"",buf2);

         tmproute->Aka=tmpaka;
      }
      else if(stricmp(cfgword,"CHANGE")==0)
      {
         if(!(tmpchange=(struct Change *)AllocMem(sizeof(struct Change),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&ChangeList,(struct jbNode *)tmpchange);

         /* Type pattern */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(buf2[0]=='*')
         {
            tmpchange->ChangeNormal=TRUE;
            tmpchange->ChangeCrash=TRUE;
            tmpchange->ChangeHold=TRUE;
            tmpchange->ChangeDirect=TRUE;
         }
         else
         {
            c=0;
            while(buf2[c]!=0)
            {
               d=c;
               while(buf2[d]!=',' && buf2[d]!=0) d++;
               if(buf2[d]==',')
               {
                  buf2[d]=0;
                  d++;
               }

               if(stricmp(&buf2[c],"NORMAL")==0)
                  tmpchange->ChangeNormal=TRUE;

               else if(stricmp(&buf2[c],"CRASH")==0)
                  tmpchange->ChangeCrash=TRUE;

               else if(stricmp(&buf2[c],"HOLD")==0)
                  tmpchange->ChangeHold=TRUE;

               else if(stricmp(&buf2[c],"DIRECT")==0)
                  tmpchange->ChangeDirect=TRUE;

               else
                  ConfigError("Unknown mail type \"%s\"",buf2);

               c=d;
            }
         }

         /* Node pattern */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4DPat(buf2,&tmpchange->Pattern)))
            ConfigError("Invalid node pattern \"%s\"",buf2);

         /* New type */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(stricmp(buf2,"NORMAL")==0)
            tmpchange->DestPri=PKTS_NORMAL;

         else if(stricmp(buf2,"CRASH")==0)
            tmpchange->DestPri=PKTS_CRASH;

         else if(stricmp(buf2,"HOLD")==0)
            tmpchange->DestPri=PKTS_HOLD;

         else if(stricmp(buf2,"DIRECT")==0)
            tmpchange->DestPri=PKTS_DIRECT;

         else
            ConfigError("Unknown mail type \"%s\"",buf2);
      }
      else if(stricmp(cfgword,"REMAP")==0)
      {
         if(!(tmpremap=(struct Remap *)AllocMem(sizeof(struct Remap),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&RemapList,(struct jbNode *)tmpremap);

         /* Type pattern */

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         strcpy(tmpremap->Pattern,buf2);

         if(ParsePatternNoCase(buf2,tmpremap->ParsedPattern,402)==-1)
            ConfigError("Invalid AmigaDOS pattern \"%s\"",buf2);

         if(!(jbstrcpy(tmpremap->NewTo,cfgbuf,36)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4DDestPat(buf2,&tmpremap->DestPat)))
            ConfigError("Invalid destination pattern \"%s\"",buf2);
      }
      else if(stricmp(cfgword,"REMAPNODE")==0)
      {
         if(!(tmpremapnode=(struct Remap *)AllocMem(sizeof(struct RemapNode),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&RemapNodeList,(struct jbNode *)tmpremapnode);

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4DPat(buf2,&tmpremapnode->NodePat)))
            ConfigError("Invalid node pattern \"%s\"",buf2);

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4DDestPat(buf2,&tmpremapnode->DestPat)))
            ConfigError("Invalid node pattern \"%s\"",buf2);
      }
      else if(stricmp(cfgword,"ROBOTNAME")==0)
      {
         if(!(tmprobot=(struct Robot *)AllocMem(sizeof(struct Robot),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&RobotList,(struct jbNode *)tmprobot);

         if(!(jbstrcpy(tmprobot->Pattern,cfgbuf,200)))
            ConfigError("Missing argument");

         if(ParsePatternNoCase(tmprobot->Pattern,tmprobot->ParsedPattern,402)==-1)
            ConfigError("Invalid AmigaDOS pattern \"%s\"",buf2);

         if(!(jbstrcpy(tmprobot->Command,cfgbuf,200)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"AREALIST")==0)
      {
         if(!(tmparealist=(struct Arealist *)AllocMem(sizeof(struct Arealist),MEMF_CLEAR)))
            ConfigNoMem();

         jbAddNode(&ArealistList,(struct jbNode *)tmparealist);

         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4D(buf2,&tmp4d)))
            ConfigError("Invalid node number \"%s\"",buf2);

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

         if(!tmpnode)
            ConfigError("Unconfigured node \"%s\"",buf2);

         tmparealist->Node=tmpnode;

         if(!(jbstrcpy(tmparealist->AreaFile,cfgbuf,80)))
            ConfigError("Missing argument");

         while(jbstrcpy(buf2,cfgbuf,200))
         {
            if(stricmp(buf2,"FORWARD")==0)
            {
               tmparealist->Flags|=AREALIST_FORWARD;
            }
            else if(stricmp(buf2,"DESC")==0)
            {
               tmparealist->Flags|=AREALIST_DESC;
            }
            else if(stricmp(buf2,"GROUP")==0)
            {
               if(!jbstrcpy(buf2,cfgbuf,200))
                  ConfigError("Missing argument");

               if(!CorrectFlags(buf2))
                  ConfigError("Invalid group \"%s\"",buf2);

               tmparealist->Group=buf2[0];
            }
            else
            {
               ConfigError("Unknown switch \"%s\"",buf2);
            }
         }
      }
      else if(stricmp(cfgword,"REMOTEAF")==0)
      {
         if(!LastCNode)
            ConfigError("No NODE line");

         if(!(jbstrcpy(LastCNode->RemoteAFName,cfgbuf,36)))
            ConfigError("Missing argument");

         if(!(jbstrcpy(LastCNode->RemoteAFPw,cfgbuf,72)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"REMOTESYSOP")==0)
      {
         if(!LastCNode)
            ConfigError("No NODE line");

         if(!(jbstrcpy(LastCNode->SysopName,cfgbuf,36)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"AUTOADD")==0)
      {
         cfg_Flags|=CFG_AUTOADD;
      }
      else if(stricmp(cfgword,"STRIPRE")==0)
      {
         cfg_Flags|=CFG_STRIPRE;
      }
      else if(stricmp(cfgword,"FORCEINTL")==0)
      {
         cfg_Flags|=CFG_FORCEINTL;
      }
      else if(stricmp(cfgword,"UMSMAUSGATE")==0)
      {
         cfg_Flags|=CFG_UMSMAUSGATE;
      }
      else if(stricmp(cfgword,"UMSIGNOREORIGINDOMAIN")==0)
      {
         cfg_Flags|=CFG_UMSIGNOREORIGINDOMAIN;
      }
      else if(stricmp(cfgword,"UMSEMPTYTOALL")==0)
      {
         cfg_Flags|=CFG_UMSEMPTYTOALL;
      }
      else if(stricmp(cfgword,"BOUNCEHEADERONLY")==0)
      {
         cfg_Flags|=CFG_BOUNCEHEADERONLY;
      }
      else if(stricmp(cfgword,"REMOVEWHENFEED")==0)
      {
         cfg_Flags|=CFG_REMOVEWHENFEED;
      }
      else if(stricmp(cfgword,"INCLUDEFORWARD")==0)
      {
         cfg_Flags2|=CFG2_INCLUDEFORWARD;
      }
      else if(stricmp(cfgword,"NOROUTE")==0)
      {
         cfg_Flags|=CFG_NOROUTE;
      }
      else if(stricmp(cfgword,"UMSKEEPORIGIN")==0)
      {
         cfg_Flags|=CFG_UMSKEEPORIGIN;
      }
      else if(stricmp(cfgword,"ANSWERRECEIPT")==0)
      {
         cfg_Flags|=CFG_ANSWERRECEIPT;
      }
      else if(stricmp(cfgword,"ANSWERAUDIT")==0)
      {
         cfg_Flags|=CFG_ANSWERAUDIT;
      }
      else if(stricmp(cfgword,"CHECKSEENBY")==0)
      {
         cfg_Flags|=CFG_CHECKSEENBY;
      }
      else if(stricmp(cfgword,"CHECKPKTDEST")==0)
      {
         cfg_Flags|=CFG_CHECKPKTDEST;
      }
      else if(stricmp(cfgword,"PATH3D")==0)
      {
         cfg_Flags|=CFG_PATH3D;
      }
      else if(stricmp(cfgword,"XLATMSG")==0)
      {
         cfg_Flags|=CFG_XLATMSG;
      }
      else if(stricmp(cfgword,"MSGHIGHWATER")==0)
      {
         cfg_Flags|=CFG_MSGHIGHWATER;
      }
      else if(stricmp(cfgword,"MSGWRITEBACK")==0)
      {
         cfg_Flags|=CFG_MSGWRITEBACK;
      }
      else if(stricmp(cfgword,"IMPORTEMPTYNETMAIL")==0)
      {
         cfg_Flags|=CFG_IMPORTEMPTYNETMAIL;
      }
      else if(stricmp(cfgword,"IMPORTAREAFIX")==0)
      {
         cfg_Flags|=CFG_IMPORTAREAFIX;
      }
      else if(stricmp(cfgword,"AREAFIXREMOVE")==0)
      {
         cfg_Flags|=CFG_AREAFIXREMOVE;
      }
      else if(stricmp(cfgword,"CHANGEUMSMSGID")==0)
      {
         cfg_Flags|=CFG_CHANGEUMSMSGID;
      }
      else if(stricmp(cfgword,"NODIRECTATTACH")==0)
      {
         cfg_Flags|=CFG_NODIRECTATTACH;
      }
      else if(stricmp(cfgword,"BOUNCEPOINTS")==0)
      {
         cfg_Flags|=CFG_BOUNCEPOINTS;
      }
      else if(stricmp(cfgword,"IMPORTSEENBY")==0)
      {
         cfg_Flags|=CFG_IMPORTSEENBY;
      }
      else if(stricmp(cfgword,"UNATTENDED")==0)
      {
         cfg_Flags|=CFG_UNATTENDED;
      }
      else if(stricmp(cfgword,"WEEKDAYNAMING")==0)
      {
         cfg_Flags|=CFG_WEEKDAYNAMING;
      }
      else if(stricmp(cfgword,"ADDTID")==0)
      {
         cfg_Flags|=CFG_ADDTID;
      }
      else if(stricmp(cfgword,"CODEPAGE865")==0)
      {
         cfg_Flags|=CFG_CODEPAGE865;
      }
      else if(stricmp(cfgword,"ALLOWRESCAN")==0)
      {
         cfg_Flags|=CFG_ALLOWRESCAN;
      }
      else if(stricmp(cfgword,"FORWARDPASSTHRU")==0)
      {
         cfg_Flags|=CFG_FORWARDPASSTHRU;
      }
      else if(stricmp(cfgword,"NOTOUCHHWTOSSING")==0)
      {
         cfg_Flags|=CFG_NOTOUCHHWTOSSING;
      }
      else if(stricmp(cfgword,"MAXPKTSIZE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         cfg_MaxPktSize=atoi(buf2)*1024;
      }
      else if(stricmp(cfgword,"MAXBUNDLESIZE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         cfg_MaxBundleSize=atoi(buf2)*1024;
      }
      else if(stricmp(cfgword,"DEFAULTZONE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         cfg_DefaultZone=atoi(buf2);
      }
      else if(stricmp(cfgword,"UMSNAME")==0)
      {
         if(!(jbstrcpy(cfg_UMSName,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"UMSPASSWORD")==0)
      {
         if(!(jbstrcpy(cfg_UMSPassword,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"UMSSERVER")==0)
      {
         if(!(jbstrcpy(cfg_UMSServer,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"UMSGATEWAYNAME")==0)
      {
         if(!(jbstrcpy(cfg_UMSGatewayName,cfgbuf,36)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"GATEWAYNAME")==0)
      {
         if(!(jbstrcpy(cfg_GatewayName,cfgbuf,80)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"GATEWAYNODE")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         if(!(Parse4D(buf2,&cfg_GatewayNode)))
            ConfigError("Missing argument");
      }
      else if(stricmp(cfgword,"AREAFIXMAXLINES")==0)
      {
         if(!(jbstrcpy(buf2,cfgbuf,200)))
            ConfigError("Missing argument");

         cfg_AreaFixMaxLines=atoi(buf2);
      }
      else if(cfgbuf[0]!=10 && cfgbuf[0]!=0 && cfgbuf[0]!=';')
         ConfigError("Unknown keyword");
   }

   jbClose(cfgfh);

   if(cfg_TempDir[0]==0)      strcpy(cfg_TempDir,cfg_Inbound);
   if(cfg_PacketCreate[0]==0) strcpy(cfg_PacketCreate,cfg_Outbound);
   if(cfg_PacketDir[0]==0)    strcpy(cfg_PacketDir,cfg_Outbound);

   if(cfg_Flags & CFG_AUTOADD)
   {
      for(tmpnode=CNodeList.First;tmpnode;tmpnode=tmpnode->Next)
         tmpnode->Flags |= NODE_AUTOADD;
   }
   
   return(TRUE);
}

BOOL CorrectFlags(UBYTE *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);
}

ResetConfig()
{
   int c;

   saveconfig=FALSE;

   strcpy(cfg_Sysop,"Sysop");
   strcpy(cfg_Inbound,"MAIL:Inbound");
   strcpy(cfg_Outbound,"MAIL:Outbound");
   strcpy(cfg_TempDir,"");
   strcpy(cfg_PacketCreate,"");
   strcpy(cfg_PacketDir,"");
   strcpy(cfg_LogFile,"PROGDIR:CrashMail.log");
   strcpy(cfg_StatsFile,"PROGDIR:CrashMail.stats");
   strcpy(cfg_DupeFile,"PROGDIR:CrashMail.dupes");
   strcpy(cfg_DefaultOrigin,"Default origin");
   strcpy(cfg_NodeList,"NODELIST:");
   cfg_NodeListType=NODELIST_GOTCHA;

   strcpy(cfg_GatewayName,"");

   cfg_GatewayNode.Zone=0;
   cfg_GatewayNode.Net=0;
   cfg_GatewayNode.Node=0;
   cfg_GatewayNode.Point=0;

   cfg_LogLevel=3;
   cfg_DupeSize=200;
   cfg_MaxPktSize=0;
   cfg_MaxBundleSize=0;

   cfg_LogBufferLines=10;
   cfg_LogBufferSecs=3;

   cfg_LocalCharset=NULL;

   strcpy(cfg_UMSName,"CrashMail");
   strcpy(cfg_UMSPassword,"");
   strcpy(cfg_UMSServer,"default");
   cfg_UMSGatewayName[0]=0;

   cfg_Flags=0;
   cfg_DupeMode=0;
   cfg_LoopMode=0;

   cfg_DefaultZone=2;

   for(c=0;c<26;c++)
      cfg_GroupNames[c][0]=0;

   cfg_AreaFixMaxLines=0;

   jbNewList(&AkaList);
   jbNewList(&AreaList);
   jbNewList(&CNodeList);
   jbNewList(&PackerList);
   jbNewList(&RouteList);
   jbNewList(&FileAttachList);
   jbNewList(&BounceList);
   jbNewList(&ChangeList);
   jbNewList(&RemapList);
   jbNewList(&RemapNodeList);
   jbNewList(&RobotList);
   jbNewList(&CharsetList);
   jbNewList(&AreaFixList);
   jbNewList(&ArealistList);
}

WriteString(struct jbFile *fh,UBYTE *name,UBYTE *str);
WriteSwitch(struct jbFile *fh,UBYTE *name,ULONG set);
WriteNode(struct jbFile *fh,struct Node4D *n4d);
WriteNode4DPat(struct jbFile *fh,struct Node4DPat *n4dpat);
WriteNode4DDestPat(struct jbFile *fh,struct Node4DPat *n4dpat);
WriteNode2D(struct jbFile *fh,struct Node4D *n4d);
WriteNode2DPat(struct jbFile *fh,struct Node2DPat *n4dpat);
WriteCharsetName(struct jbFile *fh,UBYTE *chrs);
SafeWrite(struct jbFile *fh,UBYTE *str);

char fprintfbuf[2000];

void jbFPrintf(struct jbFile *jbfh,UBYTE *fmt,...)
{
   va_list args;
   va_start(args, fmt);

   vsprintf(fprintfbuf,fmt,args);
   jbWrite(jbfh,fprintfbuf,strlen(fprintfbuf));
   va_end(args);
}

BOOL WriteConfig(UBYTE *cfg)
{
   UBYTE cfgtemp[100];
   UBYTE cfgbak[100];
   ULONG c;
   struct jbFile *jbfh;
   UBYTE date[40],time[40];
   struct DateTime dt;

   struct Aka           *tmpaka;
   struct ConfigNode    *tmpnode;
   struct Area          *tmparea;
   struct Packer        *tmppacker;
   struct Route         *tmproute;
   struct ImportNode    *tmpinode;
   struct PatternNode   *tmppatternnode;
   struct Change        *tmpchange;
   struct Remap         *tmpremap;
   struct RemapNode     *tmpremapnode;
   struct Robot         *tmprobot;
   struct CharsetAlias  *tmpcharsetalias;
   struct AreaFixName   *tmpareafixname;
   struct Arealist      *tmparealist;

   struct AddNode    *tmpaddnode;
   struct RemNode    *tmpremnode;
   struct TossNode   *tmptnode;
   struct BannedNode *tmpbnode;

   saveconfig=FALSE;

   strcpy(cfgtemp,cfg);
   strcat(cfgtemp,".tmp");

   strcpy(cfgbak,cfg);
   strcat(cfgbak,".bak");

   if(!(jbfh=jbOpen(cfgtemp,MODE_NEWFILE,5000)))
   {
      Printf("Unable to write to config file %s\n",(long)cfgtemp);
      return;
   }

   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);

   jbFPrintf(jbfh,"; Generated by %s\n; %s %s\n",config_version,date,time);

   jbFPrintf(jbfh,"\n; General\n\n");

   WriteString(jbfh,"SYSOP",cfg_Sysop);
   jbFPrintf(jbfh,"\n");

   WriteString(jbfh,"LOGFILE",cfg_LogFile);
   jbFPrintf(jbfh,"LOGLEVEL %lu\n",cfg_LogLevel);

   jbFPrintf(jbfh,"LOGBUFFERSECS %lu\n",cfg_LogBufferSecs);
   jbFPrintf(jbfh,"LOGBUFFERLINES %lu\n",cfg_LogBufferLines);
   jbFPrintf(jbfh,"\n");

   jbFPrintf(jbfh,"DUPEFILE ");
   SafeWrite(jbfh,cfg_DupeFile);
   jbFPrintf(jbfh," %lu\n",cfg_DupeSize/1024);

   if(cfg_DupeMode == DUPE_IGNORE)
      jbFPrintf(jbfh,"DUPEMODE IGNORE\n\n");

   if(cfg_DupeMode == DUPE_KILL)
      jbFPrintf(jbfh,"DUPEMODE KILL\n\n");

   if(cfg_DupeMode == DUPE_BAD)
      jbFPrintf(jbfh,"DUPEMODE BAD\n\n");

   if(cfg_LoopMode == LOOP_IGNORE)
      jbFPrintf(jbfh,"LOOPMODE IGNORE\n\n");

   if(cfg_LoopMode == LOOP_LOG)
      jbFPrintf(jbfh,"LOOPMODE LOG\n\n");

   if(cfg_LoopMode == LOOP_LOGBAD)
      jbFPrintf(jbfh,"LOOPMODE LOG+BAD\n\n");

   jbFPrintf(jbfh,"MAXPKTSIZE %lu\n",cfg_MaxPktSize/1024);
   jbFPrintf(jbfh,"MAXBUNDLESIZE %lu\n\n",cfg_MaxBundleSize/1024);

   jbFPrintf(jbfh,"DEFAULTZONE %lu\n\n",cfg_DefaultZone);

   jbFPrintf(jbfh,"LOCALCHRS ");
   WriteCharsetName(jbfh,cfg_LocalCharset);
   jbFPrintf(jbfh,"\n");
   WriteString(jbfh,"DEFAULTORIGIN",cfg_DefaultOrigin);

   jbFPrintf(jbfh,"\n; Paths\n\n");

   WriteString(jbfh,"INBOUND",cfg_Inbound);
   WriteString(jbfh,"OUTBOUND",cfg_Outbound);
   WriteString(jbfh,"STATSFILE",cfg_StatsFile);
   WriteString(jbfh,"TEMPDIR",cfg_TempDir);
   WriteString(jbfh,"CREATEPKTDIR",cfg_PacketCreate);
   WriteString(jbfh,"PACKETDIR",cfg_PacketDir);

   jbFPrintf(jbfh,"\n");
   jbFPrintf(jbfh,"NODELIST ");
   SafeWrite(jbfh,cfg_NodeList);

   if(cfg_NodeListType == NODELIST_TRAPLIST)
      jbFPrintf(jbfh," TRAPLIST");

   if(cfg_NodeListType == NODELIST_GOTCHA)
      jbFPrintf(jbfh," GOTCHA");

   jbFPrintf(jbfh,"\n");

   jbFPrintf(jbfh,"\n; Switches\n\n");

/* WriteSwitch(jbfh,"AUTOADD",cfg_Flags & CFG_AUTOADD); */

   WriteSwitch(jbfh,"STRIPRE",cfg_Flags & CFG_STRIPRE);
   WriteSwitch(jbfh,"FORCEINTL",cfg_Flags & CFG_FORCEINTL);
   WriteSwitch(jbfh,"UMSMAUSGATE",cfg_Flags & CFG_UMSMAUSGATE);
   WriteSwitch(jbfh,"NOROUTE",cfg_Flags & CFG_NOROUTE);
   WriteSwitch(jbfh,"UMSKEEPORIGIN",cfg_Flags & CFG_UMSKEEPORIGIN);
   WriteSwitch(jbfh,"ANSWERRECEIPT",cfg_Flags & CFG_ANSWERRECEIPT);
   WriteSwitch(jbfh,"ANSWERAUDIT",cfg_Flags & CFG_ANSWERAUDIT);
   WriteSwitch(jbfh,"CHECKSEENBY",cfg_Flags & CFG_CHECKSEENBY);
   WriteSwitch(jbfh,"CHECKPKTDEST",cfg_Flags & CFG_CHECKPKTDEST);
   WriteSwitch(jbfh,"PATH3D",cfg_Flags & CFG_PATH3D);
   WriteSwitch(jbfh,"XLATMSG",cfg_Flags & CFG_XLATMSG);
   WriteSwitch(jbfh,"MSGHIGHWATER",cfg_Flags & CFG_MSGHIGHWATER);
   WriteSwitch(jbfh,"MSGWRITEBACK",cfg_Flags & CFG_MSGWRITEBACK);
   WriteSwitch(jbfh,"IMPORTEMPTYNETMAIL",cfg_Flags & CFG_IMPORTEMPTYNETMAIL);
   WriteSwitch(jbfh,"IMPORTAREAFIX",cfg_Flags & CFG_IMPORTAREAFIX);
   WriteSwitch(jbfh,"CHANGEUMSMSGID",cfg_Flags & CFG_CHANGEUMSMSGID);
   WriteSwitch(jbfh,"NODIRECTATTACH",cfg_Flags & CFG_NODIRECTATTACH);
   WriteSwitch(jbfh,"BOUNCEPOINTS",cfg_Flags & CFG_BOUNCEPOINTS);
   WriteSwitch(jbfh,"IMPORTSEENBY",cfg_Flags & CFG_IMPORTSEENBY);
   WriteSwitch(jbfh,"UNATTENDED",cfg_Flags & CFG_UNATTENDED);
   WriteSwitch(jbfh,"AREAFIXREMOVE",cfg_Flags & CFG_AREAFIXREMOVE);
   WriteSwitch(jbfh,"WEEKDAYNAMING",cfg_Flags & CFG_WEEKDAYNAMING);
   WriteSwitch(jbfh,"ADDTID",cfg_Flags & CFG_ADDTID);
   WriteSwitch(jbfh,"CODEPAGE865",cfg_Flags & CFG_CODEPAGE865);
   WriteSwitch(jbfh,"ALLOWRESCAN",cfg_Flags & CFG_ALLOWRESCAN);
   WriteSwitch(jbfh,"FORWARDPASSTHRU",cfg_Flags & CFG_FORWARDPASSTHRU);
   WriteSwitch(jbfh,"NOTOUCHHWTOSSING",cfg_Flags & CFG_NOTOUCHHWTOSSING);
   WriteSwitch(jbfh,"UMSIGNOREORIGINDOMAIN",cfg_Flags & CFG_UMSIGNOREORIGINDOMAIN);
   WriteSwitch(jbfh,"UMSEMPTYTOALL",cfg_Flags & CFG_UMSEMPTYTOALL);
   WriteSwitch(jbfh,"BOUNCEHEADERONLY",cfg_Flags & CFG_BOUNCEHEADERONLY);
   WriteSwitch(jbfh,"REMOVEWHENFEED",cfg_Flags & CFG_REMOVEWHENFEED);
   WriteSwitch(jbfh,"INCLUDEFORWARD",cfg_Flags2 & CFG2_INCLUDEFORWARD);

   jbFPrintf(jbfh,"\n; UMS\n\n");

   WriteString(jbfh,"UMSNAME",cfg_UMSName);
   WriteString(jbfh,"UMSPASSWORD",cfg_UMSPassword);
   WriteString(jbfh,"UMSSERVER",cfg_UMSServer);
   WriteString(jbfh,"UMSGATEWAYNAME",cfg_UMSGatewayName);
   jbFPrintf(jbfh,"\n");
   WriteString(jbfh,"GATEWAYNAME",cfg_GatewayName);
   jbFPrintf(jbfh,"GATEWAYNODE ");
   WriteNode(jbfh,&cfg_GatewayNode);
   jbFPrintf(jbfh,"\n");

   jbFPrintf(jbfh,"\n; Groupnames\n\n");

   for(c=0;c<26;c++)
   {
      if(cfg_GroupNames[c][0]!=0)
      {
         jbFPrintf(jbfh,"GROUPNAME %lc ",'A'+c);
         SafeWrite(jbfh,cfg_GroupNames[c]);
         jbFPrintf(jbfh,"\n");
      }
   }

   jbFPrintf(jbfh,"\n; Charset aliases\n\n");

   for(tmpcharsetalias=CharsetList.First;tmpcharsetalias;tmpcharsetalias=tmpcharsetalias->Next)
   {
      jbFPrintf(jbfh,"CHARSETALIAS ");
      SafeWrite(jbfh,tmpcharsetalias->Name);
      jbFPrintf(jbfh," ");
      WriteCharsetName(jbfh,tmpcharsetalias->CHRS);
      jbFPrintf(jbfh,"\n");
   }

   if(BounceList.First)
   {
      jbFPrintf(jbfh,"\n; Bounce\n\n");

      jbFPrintf(jbfh,"BOUNCE");

      for(tmppatternnode=BounceList.First;tmppatternnode;tmppatternnode=tmppatternnode->Next)
      {
         jbFPrintf(jbfh," ");
         WriteNode4DPat(jbfh,&tmppatternnode->Pattern);
      }

      jbFPrintf(jbfh,"\n");
   }

   if(FileAttachList.First)
   {
      jbFPrintf(jbfh,"\n; Fileattach\n\n");

      jbFPrintf(jbfh,"FILEATTACH");

      for(tmppatternnode=FileAttachList.First;tmppatternnode;tmppatternnode=tmppatternnode->Next)
      {
         jbFPrintf(jbfh," ");
         WriteNode4DPat(jbfh,&tmppatternnode->Pattern);
      }

      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; Change\n\n");

   for(tmpchange=ChangeList.First;tmpchange;tmpchange=tmpchange->Next)
   {
      jbFPrintf(jbfh,"CHANGE ");

      if(tmpchange->ChangeNormal && tmpchange->ChangeCrash && tmpchange->ChangeHold && tmpchange->ChangeDirect)
      {
         jbFPrintf(jbfh,"* ");
      }
      else
      {
         c=0;

         if(tmpchange->ChangeNormal)
         {
            if(c)
               jbFPrintf(jbfh,",Normal");

            else
               jbFPrintf(jbfh,"Normal");
            c=1;
         }

         if(tmpchange->ChangeCrash)
         {
            if(c)
               jbFPrintf(jbfh,",Crash");

            else
               jbFPrintf(jbfh,"Crash");
            c=1;
         }

         if(tmpchange->ChangeHold)
         {
            if(c)
               jbFPrintf(jbfh,",Hold");

            else
               jbFPrintf(jbfh,"Hold");
            c=1;
         }

         if(tmpchange->ChangeDirect)
         {
            if(c)
               jbFPrintf(jbfh,",Direct");

            else
               jbFPrintf(jbfh,"Direct");
            c=1;
         }
      }

      jbFPrintf(jbfh," ");
      WriteNode4DPat(jbfh,&tmpchange->Pattern);

      jbFPrintf(jbfh," ");

      if(tmpchange->DestPri==PKTS_NORMAL)
         jbFPrintf(jbfh,"Normal\n");

      if(tmpchange->DestPri==PKTS_CRASH)
         jbFPrintf(jbfh,"Crash\n");

      if(tmpchange->DestPri==PKTS_HOLD)
         jbFPrintf(jbfh,"Hold\n");

      if(tmpchange->DestPri==PKTS_DIRECT)
         jbFPrintf(jbfh,"Direct\n");
   }

   jbFPrintf(jbfh,"\n; Packers\n\n");

   for(tmppacker=PackerList.First;tmppacker;tmppacker=tmppacker->Next)
   {
      jbFPrintf(jbfh,"PACKER ");
      SafeWrite(jbfh,tmppacker->Name);
      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmppacker->Packer);
      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmppacker->Unpacker);
      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmppacker->Recog);
      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; AKA\n\n");

   for(tmpaka=AkaList.First;tmpaka;tmpaka=tmpaka->Next)
   {
      jbFPrintf(jbfh,"AKA ");
      WriteNode(jbfh,&tmpaka->Node);
      jbFPrintf(jbfh,"\n");

      if(tmpaka->AddList.First)
      {
         for(tmpaddnode=tmpaka->AddList.First;tmpaddnode;tmpaddnode=tmpaddnode->Next)
         {
            jbFPrintf(jbfh,"ADDNODE ");
            WriteNode2D(jbfh,&tmpaddnode->Node);
            jbFPrintf(jbfh,"\n");
         }
      }

      if(tmpaka->RemList.First)
      {
         for(tmpremnode=tmpaka->RemList.First;tmpremnode;tmpremnode=tmpremnode->Next)
         {
            jbFPrintf(jbfh,"REMNODE ");
            WriteNode2DPat(jbfh,&tmpremnode->NodePat);
            jbFPrintf(jbfh,"\n");
         }
      }

      if(tmpaka->FakeNet != 0)
         jbFPrintf(jbfh,"FAKENET %lu\n",tmpaka->FakeNet);

      if(tmpaka->Domain[0]!=0)
         WriteString(jbfh,"DOMAIN",tmpaka->Domain);

      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; Nodes\n\n");

   for(tmpnode=CNodeList.First;tmpnode;tmpnode=tmpnode->Next)
   {
      jbFPrintf(jbfh,"NODE ");
      WriteNode(jbfh,&tmpnode->Node);
      jbFPrintf(jbfh," ");

      if(tmpnode->Packer)
         SafeWrite(jbfh,tmpnode->Packer->Name);

      else
         SafeWrite(jbfh,"");

      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmpnode->PacketPW);

      if(tmpnode->Flags & NODE_STONEAGE)
         jbFPrintf(jbfh," STONEAGE");

      if(tmpnode->Flags & NODE_PASSIVE)
         jbFPrintf(jbfh," PASSIVE");

      if(tmpnode->Flags & NODE_NOTIFY)
         jbFPrintf(jbfh," NOTIFY");

      if(tmpnode->Flags & NODE_NOSEENBY)
         jbFPrintf(jbfh," NOSEENBY");

      if(tmpnode->Flags & NODE_TINYSEENBY)
         jbFPrintf(jbfh," TINYSEENBY");

      if(tmpnode->Flags & NODE_FORWARDREQ)
         jbFPrintf(jbfh," FORWARDREQ");

      if(tmpnode->Flags & NODE_PACKNETMAIL)
         jbFPrintf(jbfh," PACKNETMAIL");

      if(tmpnode->Flags & NODE_SENDAREAFIX)
         jbFPrintf(jbfh," SENDAREAFIX");

      if(tmpnode->Flags & NODE_SENDTEXT)
         jbFPrintf(jbfh," SENDTEXT");

      if(tmpnode->Flags & NODE_AUTOADD)
         jbFPrintf(jbfh," AUTOADD");

      jbFPrintf(jbfh,"\n");

      if(tmpnode->AreafixPW[0] || tmpnode->Groups[0] || tmpnode->ReadOnlyGroups[0] || tmpnode->AddGroups[0])
      {
         UBYTE flagbuf[100];

         jbFPrintf(jbfh,"AREAFIXINFO ");
         SafeWrite(jbfh,tmpnode->AreafixPW);
         jbFPrintf(jbfh," ");

         strcpy(flagbuf,tmpnode->Groups);

         if(tmpnode->ReadOnlyGroups[0]!=0 || tmpnode->AddGroups[0]!=0)
         {
            strcat(flagbuf,"!");
            strcat(flagbuf,tmpnode->ReadOnlyGroups);
         }

         if(tmpnode->AddGroups[0]!=0)
         {
            strcat(flagbuf,"!");
            strcat(flagbuf,tmpnode->AddGroups);
         }

         SafeWrite(jbfh,flagbuf);
         jbFPrintf(jbfh,"\n");
      }

      if(tmpnode->RemoteAFName[0])
      {
         jbFPrintf(jbfh,"REMOTEAF ");
         SafeWrite(jbfh,tmpnode->RemoteAFName);
         jbFPrintf(jbfh," ");
         SafeWrite(jbfh,tmpnode->RemoteAFPw);
         jbFPrintf(jbfh,"\n");
      }

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

      if(tmpnode->DefaultGroup)
         jbFPrintf(jbfh,"DEFAULTGROUP %lc\n",tmpnode->DefaultGroup);

      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; Remap\n\n");

   for(tmpremap=RemapList.First;tmpremap;tmpremap=tmpremap->Next)
   {
      jbFPrintf(jbfh,"REMAP ");
      SafeWrite(jbfh,tmpremap->Pattern);
      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmpremap->NewTo);
      jbFPrintf(jbfh," ");
      WriteNode4DDestPat(jbfh,&tmpremap->DestPat);
      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n");

   for(tmpremapnode=RemapNodeList.First;tmpremapnode;tmpremapnode=tmpremapnode->Next)
   {
      jbFPrintf(jbfh,"REMAPNODE ");
      WriteNode4DPat(jbfh,&tmpremapnode->NodePat);
      jbFPrintf(jbfh," ");
      WriteNode4DDestPat(jbfh,&tmpremapnode->DestPat);
      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; Robotnames\n\n");

   for(tmprobot=RobotList.First;tmprobot;tmprobot=tmprobot->Next)
   {
      jbFPrintf(jbfh,"ROBOTNAME ");
      SafeWrite(jbfh,tmprobot->Pattern);
      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmprobot->Command);
      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; AreaFix\n\n");

   WriteString(jbfh,"AREAFIXHELP",cfg_AreaFixHelp);
   jbFPrintf(jbfh,"AREAFIXMAXLINES %ld\n",cfg_AreaFixMaxLines);

   jbFPrintf(jbfh,"\n");

   for(tmpareafixname=AreaFixList.First;tmpareafixname;tmpareafixname=tmpareafixname->Next)
   {
      WriteString(jbfh,"AREAFIXNAME",tmpareafixname->Name);
   }

   jbFPrintf(jbfh,"\n");

   for(tmparealist=ArealistList.First;tmparealist;tmparealist=tmparealist->Next)
   {
      jbFPrintf(jbfh,"AREALIST ");
      WriteNode(jbfh,&tmparealist->Node->Node);
      jbFPrintf(jbfh," ");
      SafeWrite(jbfh,tmparealist->AreaFile);

     if(tmparealist->Group)
         jbFPrintf(jbfh," GROUP %lc",tmparealist->Group);

     if(tmparealist->Flags & AREALIST_FORWARD)
         jbFPrintf(jbfh," FORWARD");

     if(tmparealist->Flags & AREALIST_DESC)
         jbFPrintf(jbfh," DESC");

      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; Routing\n\n");

   for(tmproute=RouteList.First;tmproute;tmproute=tmproute->Next)
   {
      jbFPrintf(jbfh,"ROUTE ");
      WriteNode4DPat(jbfh,&tmproute->Pattern);
      jbFPrintf(jbfh," ");
      WriteNode4DDestPat(jbfh,&tmproute->DestPat);
      jbFPrintf(jbfh," ");
      WriteNode(jbfh,&tmproute->Aka->Node);
      jbFPrintf(jbfh,"\n");
   }

   jbFPrintf(jbfh,"\n; Areas\n\n");

   for(tmparea=AreaList.First;tmparea;tmparea=tmparea->Next)
   {
      if(tmparea->Flags & AREA_NETMAIL)
         jbFPrintf(jbfh,"NETMAIL ");

      else
         jbFPrintf(jbfh,"AREA ");

      SafeWrite(jbfh,tmparea->Tagname);
      jbFPrintf(jbfh," ");
      WriteNode(jbfh,&tmparea->Aka->Node);

      if(tmparea->AreaType == AREATYPE_UMS)
      {
         jbFPrintf(jbfh," UMS ");
      }
      else if(tmparea->AreaType == AREATYPE_MSG)
      {
         jbFPrintf(jbfh," MSG ");
      }
      else
      {
         jbFPrintf(jbfh," P/T ");
      }

      if(tmparea->Path[0]==0 && tmparea->AreaType == AREATYPE_UMS)
         jbFPrintf(jbfh,"Mail");

      else
         SafeWrite(jbfh,tmparea->Path);

      jbFPrintf(jbfh," ");
      WriteCharsetName(jbfh,tmparea->ExportCHRS);
      jbFPrintf(jbfh," ");
      WriteCharsetName(jbfh,tmparea->DefaultCHRS);

      jbFPrintf(jbfh,"\n");

      if(tmparea->Flags & AREA_NETMAIL)
      {
         c=0;

         for(tmpinode=tmparea->TossNodes.First;tmpinode;tmpinode=tmpinode->Next)
         {
            if(c%10==0)
            {
               if(c!=0) jbFPrintf(jbfh,"\n");
               jbFPrintf(jbfh,"IMPORT");
            }

            jbFPrintf(jbfh," ");
            WriteNode(jbfh,&tmpinode->Node);
            c++;
         }
         if(c!=0) jbFPrintf(jbfh,"\n");
      }
      else
      {
         c=0;

         for(tmptnode=tmparea->TossNodes.First;tmptnode;tmptnode=tmptnode->Next)
         {
            if(c%10==0)
            {
               if(c!=0) jbFPrintf(jbfh,"\n");
               jbFPrintf(jbfh,"EXPORT");
            }

            jbFPrintf(jbfh," ");

            if(tmptnode->Flags & TOSSNODE_READONLY)
               jbFPrintf(jbfh,"!");

            if(tmptnode->Flags & TOSSNODE_WRITEONLY)
               jbFPrintf(jbfh,"@");

            if(tmptnode->Flags & TOSSNODE_FEED)
               jbFPrintf(jbfh,"%%");

            WriteNode(jbfh,&tmptnode->ConfigNode->Node);
            c++;
         }
         if(c!=0) jbFPrintf(jbfh,"\n");
      }

      c=0;
      for(tmpbnode=tmparea->BannedNodes.First;tmpbnode;tmpbnode=tmpbnode->Next)
      {
         if(c%10==0)
         {
            if(c!=0) jbFPrintf(jbfh,"\n");
            jbFPrintf(jbfh,"BANNED");
         }

         jbFPrintf(jbfh," ");
         WriteNode(jbfh,&tmpbnode->ConfigNode->Node);
         c++;
      }
      if(c!=0) jbFPrintf(jbfh,"\n");

      if(tmparea->Description[0]!=0)
      {
         jbFPrintf(jbfh,"DESCRIPTION ");
         SafeWrite(jbfh,tmparea->Description);
         jbFPrintf(jbfh,"\n");
      }

      if(tmparea->Group)
         jbFPrintf(jbfh,"GROUP %lc\n",tmparea->Group);

      if(tmparea->KeepNum)
         jbFPrintf(jbfh,"KEEPNUM %lu\n",tmparea->KeepNum);

      if(tmparea->KeepDays)
         jbFPrintf(jbfh,"KEEPDAYS %lu\n",tmparea->KeepDays);

      if(tmparea->Flags & AREA_UNCONFIRMED)
         jbFPrintf(jbfh,"UNCONFIRMED\n");

      if(tmparea->Flags & AREA_MANDATORY)
         jbFPrintf(jbfh,"MANDATORY\n");

      if(tmparea->Flags & AREA_DEFREADONLY)
         jbFPrintf(jbfh,"DEFREADONLY\n");

      if(tmparea->Flags & AREA_IGNOREDUPES)
         jbFPrintf(jbfh,"IGNOREDUPES\n");

      if(tmparea->Flags & AREA_IGNORESEENBY)
         jbFPrintf(jbfh,"IGNORESEENBY\n");

      jbFPrintf(jbfh,"\n");
   }

   jbClose(jbfh);

   DeleteFile(cfgbak);
   Rename(cfg,cfgbak);
   Rename(cfgtemp,cfg);
}

WriteString(struct jbFile *fh,UBYTE *name,UBYTE *str)
{
   jbFPrintf(fh,"%s ",name);
   SafeWrite(fh,str);
   jbFPrintf(fh,"\n");
}

WriteSwitch(struct jbFile *fh,UBYTE *name,ULONG set)
{
   if(set)
      jbFPrintf(fh,"%s\n",name);

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

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

WriteNode4DPat(struct jbFile *fh,struct Node4DPat *n4dpat)
{
   UBYTE buf[100];

   Print4DPat(n4dpat,buf);
   SafeWrite(fh,buf);
}

WriteNode4DDestPat(struct jbFile *fh,struct Node4DPat *n4dpat)
{
   UBYTE buf[100];

   Print4DDestPat(n4dpat,buf);
   SafeWrite(fh,buf);
}

WriteNode2D(struct jbFile *fh,struct Node4D *n4d)
{
   jbFPrintf(fh,"%lu/%lu",n4d->Net,n4d->Node);
}

WriteNode2DPat(struct jbFile *fh,struct Node2DPat *n4dpat)
{
   jbFPrintf(fh,"%s/%s",n4dpat->Net,n4dpat->Node);
}

WriteCharsetName(struct jbFile *fh,UBYTE *chrs)
{
   if(chrs==(UBYTE *)CHARSET_ASCII)
      jbFPrintf(fh,"ASCII");

   if(chrs==NULL)
      jbFPrintf(fh,"LATIN-1");

   if(chrs==SF7ToAmiga || chrs==AmigaToSF7)
      jbFPrintf(fh,"SWEDISH");

   if(chrs==IbmToAmiga || chrs==AmigaToIbm)
      jbFPrintf(fh,"IBMPC");

   if(chrs==MacToAmiga || chrs==AmigaToMac)
      jbFPrintf(fh,"MAC");

   if(chrs==DefToAmiga)
      jbFPrintf(fh,"DEFAULT");
}

SafeWrite(struct jbFile *fh,UBYTE *str)
{
   ULONG c,d;
   BOOL quote=FALSE;
   UBYTE buf[300];

   if(str==NULL || str[0]==0)
   {
      jbFPrintf(fh,"\"\"");
      return;
   }

   for(c=0;c<strlen(str);c++)
      if(str[c]==' ') quote=TRUE;

   buf[0]=0;

   if(quote)
      strcat(buf,"\"");

   d=strlen(buf);

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

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

   buf[d]=0;

   if(quote)
      strcat(buf,"\"");

   jbFPrintf(fh,"%s",buf);
}

FreeConfig()
{
   struct Area *area;
   struct Aka *aka;
   struct ConfigNode *cnode;

   /* Config */

   for(area=AreaList.First;area;area=area->Next)
   {
      if(area->Flags & AREA_NETMAIL)
         jbFreeList(&area->TossNodes,area->TossNodes.First,sizeof(struct ImportNode));

      else
         jbFreeList(&area->TossNodes,area->TossNodes.First,sizeof(struct TossNode));

      jbFreeList(&area->BannedNodes,area->BannedNodes.First,sizeof(struct BannedNode));
   }

   for(aka=AkaList.First;aka;aka=aka->Next)
   {
      jbFreeList(&aka->AddList,aka->AddList.First,sizeof(struct AddNode));
      jbFreeList(&aka->RemList,aka->RemList.First,sizeof(struct RemNode));
   }

   for(cnode=CNodeList.First;cnode;cnode=cnode->Next)
      jbFreeList(&cnode->RemoteAFList,cnode->RemoteAFList.First,sizeof(struct RemoteAFCommand));

   jbFreeList(&AkaList,AkaList.First,sizeof(struct Aka));
   jbFreeList(&AreaList,AreaList.First,sizeof(struct Area));
   jbFreeList(&CNodeList,CNodeList.First,sizeof(struct ConfigNode));
   jbFreeList(&PackerList,PackerList.First,sizeof(struct Packer));
   jbFreeList(&RouteList,RouteList.First,sizeof(struct Route));
   jbFreeList(&RouteList,RouteList.First,sizeof(struct Route));
   jbFreeList(&FileAttachList,FileAttachList.First,sizeof(struct PatternNode));
   jbFreeList(&BounceList,BounceList.First,sizeof(struct PatternNode));
   jbFreeList(&ChangeList,ChangeList.First,sizeof(struct Change));
   jbFreeList(&RemapList,RemapList.First,sizeof(struct Remap));
   jbFreeList(&RemapNodeList,RemapNodeList.First,sizeof(struct RemapNode));
   jbFreeList(&RobotList,RobotList.First,sizeof(struct Robot));
   jbFreeList(&CharsetList,CharsetList.First,sizeof(struct CharsetAlias));
   jbFreeList(&AreaFixList,AreaFixList.First,sizeof(struct AreaFixName));
   jbFreeList(&ArealistList,ArealistList.First,sizeof(struct Arealist));
}

/* Använder jbcpos */

ULONG jbcpos;

BOOL jbstrcpy(UBYTE *dest,UBYTE *src,ULONG maxlen)
{
   ULONG d=0;
   UBYTE stopchar1,stopchar2;

   while(src[jbcpos]==32 || src[jbcpos]==9) jbcpos++;

   if(src[jbcpos]=='"')
   {
      jbcpos++;
      stopchar1='"';
      stopchar2=0;
   }
   else
   {
   	stopchar1=' ';
   	stopchar2=9;
   }

   while(src[jbcpos]!=stopchar1 && src[jbcpos]!=stopchar2 && src[jbcpos]!=10 && src[jbcpos]!=0 && d<maxlen-1)
   {
      if(src[jbcpos]=='\\' && src[jbcpos+1]!=0 && src[jbcpos+1]!=10)
      {
         jbcpos++;
         dest[d++]=src[jbcpos++];
      }

      else
         dest[d++]=src[jbcpos++];
   }
   dest[d]=0;
   if(src[jbcpos]==9 || src[jbcpos]==' ' || src[jbcpos]=='"') jbcpos++;

   if(d!=0 || stopchar1=='"') return(TRUE);

   return(FALSE);
}

