#include <CrashMail.h>

/*****************************************************/
/*                                                   */
/* Routines for parsing and comparing node numbers   */
/* and node patterns in 2D, 4D and 5D. Even special  */
/* handling for DestPat:s!                           */
/*                                                   */
/*****************************************************/

BOOL Parse4D(UBYTE *buf, struct Node4D *node)
{
   ULONG c=0,val=0;
   BOOL GotZone=FALSE,GotNet=FALSE,GotNode=FALSE;

   node->Zone=0;
   node->Net=0;
   node->Node=0;
   node->Point=0;

	for(c=0;c<strlen(buf);c++)
	{
		if(buf[c]==':')
		{
         if(GotZone || GotNet || GotNode) return(FALSE);
			node->Zone=val;
         GotZone=TRUE;
			val=0;
	   }
		else if(buf[c]=='/')
		{
         if(GotNet || GotNode) return(FALSE);
         node->Net=val;
         GotNet=TRUE;
			val=0;
		}
		else if(buf[c]=='.')
		{
         if(GotNode) return(FALSE);
         node->Node=val;
         GotNode=TRUE;
			val=0;
		}
		else if(buf[c]>='0' && buf[c]<='9')
		{
         val*=10;
         val+=buf[c]-'0';
		}
		else return(FALSE);
	}
   if(GotZone && !GotNet)  node->Net=val;
   else if(GotNode)        node->Point=val;
   else                    node->Node=val;

   return(TRUE);
}

int Compare4D(struct Node4D *node1,struct Node4D *node2)
{
   if(node1->Zone!=0 && node2->Zone!=0)
   {
      if(node1->Zone > node2->Zone) return(1);
      if(node1->Zone < node2->Zone) return(-1);
   }

   if(node1->Net  > node2->Net) return(1);
   if(node1->Net  < node2->Net) return(-1);

   if(node1->Node > node2->Node) return(1);
   if(node1->Node < node2->Node) return(-1);

   if(node1->Point > node2->Point) return(1);
   if(node1->Point < node2->Point) return(-1);

   return(0);
}

void Print4D(struct Node4D *n4d,UBYTE *dest)
{
   if(n4d->Point)
      sprintf(dest,"%lu:%lu/%lu.%lu",n4d->Zone,
                                     n4d->Net,
                                     n4d->Node,
                                     n4d->Point);

   else
      sprintf(dest,"%lu:%lu/%lu",n4d->Zone,
                                 n4d->Net,
                                 n4d->Node);
}

BOOL Parse4DPat(UBYTE *buf, struct Node4DPat *node)
{
   BOOL res;

   node->Zone[0]=0;
   node->Net[0]=0;
   node->Node[0]=0;
   node->Point[0]=0;

   if(strnicmp(buf,"ZONE ",5)==0)
   {
      node->Type=PAT_ZONE;
      res=rawParse4DPat(&buf[5],node);
      strcpy(node->Zone,node->Node);
      node->Net[0]=0;
      node->Node[0]=0;
      node->Point[0]=0;
   }
   else if(strnicmp(buf,"REGION ",7)==0)
   {
      node->Type=PAT_REGION;
      res=rawParse4DPat(&buf[7],node);
      node->Node[0]=0;
      node->Point[0]=0;
   }
   else if(strnicmp(buf,"NET ",4)==0)
   {
      node->Type=PAT_NET;
      res=rawParse4DPat(&buf[4],node);
      node->Node[0]=0;
      node->Point[0]=0;
   }
   else if(strnicmp(buf,"HUB ",4)==0)
   {
      node->Type=PAT_HUB;
      res=rawParse4DPat(&buf[4],node);
      node->Point[0]=0;
   }
   else if(strnicmp(buf,"NODE ",5)==0)
   {
      node->Type=PAT_NODE;
      res=rawParse4DPat(&buf[5],node);
      node->Point[0]=0;
   }
   else
   {
      node->Type=PAT_PATTERN;
      res=rawParse4DPat(buf,node);
   }

   return(res);
}

BOOL Parse4DDestPat(UBYTE *buf, struct Node4DPat *node)
{
   BOOL res;

   node->Zone[0]=0;
   node->Net[0]=0;
   node->Node[0]=0;
   node->Point[0]=0;

   res=TRUE;

   if(stricmp(buf,"ZONE")==0)
   {
      node->Type=PAT_ZONE;
   }
   else if(stricmp(buf,"REGION")==0)
   {
      node->Type=PAT_REGION;
   }
   else if(stricmp(buf,"NET")==0)
   {
      node->Type=PAT_NET;
   }
   else if(stricmp(buf,"HUB")==0)
   {
      node->Type=PAT_HUB;
   }
   else if(stricmp(buf,"NODE")==0)
   {
      node->Type=PAT_NODE;
   }
   else
   {
      node->Type=PAT_PATTERN;
      res=rawParse4DPat(buf,node);
   }

   return(res);
}

BOOL rawParse4DPat(UBYTE *buf, struct Node4DPat *node)
{
   ULONG c=0,tempc=0;
   UBYTE temp[10];
   BOOL GotZone=FALSE,GotNet=FALSE,GotNode=FALSE;

   strcpy(node->Zone,"*");
   strcpy(node->Net,"*");
   strcpy(node->Node,"*");
   strcpy(node->Point,"*");

   if(strcmp(buf,"*")==0)
      return(TRUE);

	for(c=0;c<strlen(buf);c++)
	{
		if(buf[c]==':')
		{
         if(GotZone || GotNet || GotNode) return(FALSE);
         strcpy(node->Zone,temp);
         GotZone=TRUE;
			tempc=0;
	   }
		else if(buf[c]=='/')
		{
         if(GotNet || GotNode) return(FALSE);
         strcpy(node->Net,temp);
         GotNet=TRUE;
			tempc=0;
		}
		else if(buf[c]=='.')
		{
         if(GotNode) return(FALSE);
         strcpy(node->Node,temp);
         node->Point[0]=0;
         GotNode=TRUE;
			tempc=0;
		}
		else if((buf[c]>='0' && buf[c]<='9') || buf[c]=='*' || buf[c]=='?')
		{
         if(tempc<9)
         {
            temp[tempc++]=buf[c];
            temp[tempc]=0;
         }
		}
		else return(FALSE);
	}

   if(GotZone && !GotNet)
   {
      strcpy(node->Net,temp);
   }
   else if(GotNode)
   {
      strcpy(node->Point,temp);
   }
   else
   {
      strcpy(node->Node,temp);
      strcpy(node->Point,"0");
   }

   return(TRUE);
}

BOOL Parse2DPat(UBYTE *buf, struct Node2DPat *node)
{
   ULONG c=0,tempc=0;
   UBYTE temp[10];
   BOOL GotNet=FALSE;

   strcpy(node->Net,"*");
   strcpy(node->Node,"*");

   if(strcmp(buf,"*")==0)
      return(TRUE);

	for(c=0;c<strlen(buf);c++)
	{
		if(buf[c]=='/')
		{
         if(GotNet) return(FALSE);
         strcpy(node->Net,temp);
         GotNet=TRUE;
			tempc=0;
		}
		else if((buf[c]>='0' && buf[c]<='9') || buf[c]=='*' || buf[c]=='?')
		{
         if(tempc<9)
         {
            temp[tempc++]=buf[c];
            temp[tempc]=0;
         }
		}
		else return(FALSE);
	}

   strcpy(node->Node,temp);
   return(TRUE);
}

int Compare4DPat(struct Node4DPat *nodepat,struct Node4D *node)
{
   int num;

   switch(nodepat->Type)
   {
      case PAT_PATTERN:
         if(node->Zone!=0)
            if(NodeCompare(nodepat->Zone, node->Zone )!=0) return(1);

         if(NodeCompare(nodepat->Net,  node->Net  )!=0) return(1);
         if(NodeCompare(nodepat->Node, node->Node )!=0) return(1);
         if(NodeCompare(nodepat->Point,node->Point)!=0) return(1);
         return(0);

      case PAT_ZONE:
         if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1);
         return(0);

      case PAT_REGION:
         if(cfg_NodeList[0]==0)
            return(1);

         num=nlGetRegion(node);

         if(num == -1)
            return(1);

         if(node->Zone!=0)
            if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1);

         if(NodeCompare(nodepat->Net,num)!=0) return(1);
         return(0);

      case PAT_NET:
         if(node->Zone!=0)
            if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1);

         if(NodeCompare(nodepat->Net,node->Net)!=0) return(1);
         return(0);

      case PAT_HUB:
         if(cfg_NodeList[0]==0)
            return(1);

         num=nlGetHub(node);

         if(num == -1)
            return(1);

         if(node->Zone!=0)
            if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1);

         if(NodeCompare(nodepat->Net,node->Net)!=0) return(1);
         if(NodeCompare(nodepat->Node,num)!=0) return(1);
         return(0);

      case PAT_NODE:
         if(node->Zone!=0)
            if(NodeCompare(nodepat->Zone, node->Zone )!=0) return(1);

         if(NodeCompare(nodepat->Net,  node->Net  )!=0) return(1);
         if(NodeCompare(nodepat->Node, node->Node )!=0) return(1);
         return(0);
   }
}

int Compare2DPat(struct Node2DPat *nodepat,UWORD net,UWORD node)
{
      if(NodeCompare(nodepat->Net,  net )!=0) return(1);
      if(NodeCompare(nodepat->Node, node)!=0) return(1);
      return(0);
}

int NodeCompare(UBYTE *pat,UWORD num)
{
   UBYTE buf[10],c;
   sprintf(buf,"%lu",num);

   if(pat[0]==0) return(0);

   for(c=0;c<strlen(pat);c++)
   {
      if(pat[c]=='*') return(0);
      if(pat[c]!=buf[c] && pat[c]!='?') return(1);
      if(buf[c]==0) return(1);
   }

   if(buf[c]!=0)
      return(1);

   return(0);
}

void Copy4D(struct Node4D *node1,struct Node4D *node2)
{
   node1->Zone=node2->Zone;
   node1->Net=node2->Net;
   node1->Node=node2->Node;
   node1->Point=node2->Point;
}

BOOL Check4DPatNodelist(struct Node4DPat *pat)
{
   if(cfg_NodeList[0])
      return(TRUE);

   if(pat->Type == PAT_HUB || pat->Type == PAT_REGION)
      return(FALSE);

   return(TRUE);
}

void Print4DPat(struct Node4DPat *pat,UBYTE *dest)
{
   switch(pat->Type)
   {
      case PAT_PATTERN:
         sprintf(dest,"%s:%s/%s.%s",pat->Zone,pat->Net,pat->Node,pat->Point);
         break;
      case PAT_ZONE:
         sprintf(dest,"ZONE %s",pat->Zone);
         break;
      case PAT_REGION:
         sprintf(dest,"REGION %s:%s",pat->Zone,pat->Net);
         break;
      case PAT_NET:
         sprintf(dest,"NET %s:%s",pat->Zone,pat->Net);
         break;
      case PAT_HUB:
         sprintf(dest,"HUB %s:%s/%s",pat->Zone,pat->Net,pat->Node);
         break;
      case PAT_NODE:
         sprintf(dest,"NODE %s:%s/%s",pat->Zone,pat->Net,pat->Node);
         break;
   }
}

void Print4DDestPat(struct Node4DPat *pat,UBYTE *dest)
{
   switch(pat->Type)
   {
      case PAT_PATTERN:
         sprintf(dest,"%s:%s/%s.%s",pat->Zone,pat->Net,pat->Node,pat->Point);
         break;
      case PAT_ZONE:
         sprintf(dest,"ZONE");
         break;
      case PAT_REGION:
         sprintf(dest,"REGION");
         break;
      case PAT_NET:
         sprintf(dest,"NET");
         break;
      case PAT_HUB:
         sprintf(dest,"HUB");
         break;
      case PAT_NODE:
         sprintf(dest,"NODE");
         break;
   }
}

BOOL Parse5D(UBYTE *buf, struct Node5D *node)
{
   ULONG c=0,val=0;
   BOOL GotZone=FALSE,GotNet=FALSE,GotNode=FALSE;
   UBYTE buf2[100];

   node->Domain[0]=0;
   node->Zone=0;
   node->Net=0;
   node->Node=0;
   node->Point=0;

   mystrncpy(buf2,buf,100);

   for(c=0;c<strlen(buf2);c++)
      if(buf2[c]=='@') break;

   if(buf2[c]=='@')
   {
      buf2[c]=0;
      mystrncpy(node->Domain,&buf2[c+1],20);
   }

	for(c=0;c<strlen(buf2);c++)
	{
		if(buf2[c]==':')
		{
         if(GotZone || GotNet || GotNode) return(FALSE);
			node->Zone=val;
         GotZone=TRUE;
			val=0;
	   }
		else if(buf2[c]=='/')
		{
         if(GotNet || GotNode) return(FALSE);
         node->Net=val;
         GotNet=TRUE;
			val=0;
		}
		else if(buf2[c]=='.')
		{
         if(GotNode) return(FALSE);
         node->Node=val;
         GotNode=TRUE;
			val=0;
		}
		else if(buf2[c]>='0' && buf2[c]<='9')
		{
         val*=10;
         val+=buf2[c]-'0';
		}
		else return(FALSE);
	}

   if(GotZone && !GotNet)  node->Net=val;      
   else if(GotNode)        node->Point=val;    
   else                    node->Node=val;     

   return(TRUE);
}

int CheckPacketPW(struct Node4D *node, UBYTE *pw)
{
   struct ConfigNode *cfgnode;

   for(cfgnode=CNodeList.First;cfgnode;cfgnode=cfgnode->Next)
   {
      if(Compare4D(node,&cfgnode->Node)==0)
      {
         if(cfgnode->PacketPW[0]==0) return(TRUE);
         if(stricmp(pw,cfgnode->PacketPW)!=0) return(FALSE);

         pkt_pw=TRUE;
         return(TRUE);
      }
   }
   return(TRUE);
}

ExpandPacker(UBYTE *cmd,UBYTE *dest,UBYTE *archive,UBYTE *file)
{
   ULONG c,d;

   d=0;
   for(c=0;c<strlen(cmd);c++)
   {
      if(cmd[c]=='%' && (cmd[c+1]|32)=='a')
      {
         strcpy(&dest[d],archive);
         d+=strlen(archive);
         c++;
      }
      else if(cmd[c]=='%' && (cmd[c+1]|32)=='f')
      {
         strcpy(&dest[d],file);
         d+=strlen(file);
         c++;
      }
      else if(cmd[c]=='%' && cmd[c+1]!=0)
      {
         dest[d++]=cmd[c+1];
         c++;
      }
      else dest[d++]=cmd[c];
   }
   dest[d]=0;
}

/* Scan for Pkt and Arc */

ScanForPktArc(UBYTE *dir,struct jbList *pktlist,struct jbList *arclist)
{
   BPTR l;
   struct FileInfoBlock *fib;
   struct FileToProcess *tmp;

   if(pktlist) jbNewList(pktlist);
   if(arclist) jbNewList(arclist);

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      nomem=TRUE;
      return;
   }

   if(!(l=Lock(dir,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Directory \"%s\" not found",dir);
      exitprg=TRUE;
      return;
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Unable to examine lock on \"%s\"",dir);  
      exitprg=TRUE;
      return;
   }

   if(fib->fib_DirEntryType <= 0)
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"\"%s\" is a file, not a directory!",dir);
      exitprg=TRUE;
      return;
   }

   while(ExNext(l,fib) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
   {
      if(IsPkt(fib->fib_FileName) || IsArcMail(fib->fib_FileName))
      {
         if(!(tmp=(struct FileToProcess *)AllocMem(sizeof(struct FileToProcess),MEMF_CLEAR)))
         {
            nomem=TRUE;
            break;
         }

         mystrncpy(tmp->Name,fib->fib_FileName,40);
         strcpy(tmp->Comment,fib->fib_Comment);
         tmp->Size=fib->fib_Size;
         CopyMem(&fib->fib_Date,&tmp->Date,sizeof(struct DateStamp));

         if(IsPkt(fib->fib_FileName))
         {
            if(pktlist) jbAddNode(pktlist,(struct jbNode *)tmp);
            else        FreeMem(tmp,sizeof(struct FileToProcess));
         }
         if(IsArcMail(fib->fib_FileName))
         {
            if(arclist) jbAddNode(arclist,(struct jbNode *)tmp);
            else        FreeMem(tmp,sizeof(struct FileToProcess));
         }
      }
   }

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      exitprg=TRUE;
}

ScanForPktArcShowBad(UBYTE *dir,struct jbList *pktlist,struct jbList *arclist)
{
   BPTR l;
   struct FileInfoBlock *fib;
   struct FileToProcess *tmp;

   if(pktlist) jbNewList(pktlist);
   if(arclist) jbNewList(arclist);

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      nomem=TRUE;
      return;
   }

   if(!(l=Lock(dir,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Directory \"%s\" not found",dir);
      exitprg=TRUE;
      return;
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Unable to examine lock on \"%s\"",dir);
      exitprg=TRUE;
      return;
   }

   if(fib->fib_DirEntryType <= 0)
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"\"%s\" is a file, not a directory!",dir);
      exitprg=TRUE;
      return;
   }

   while(ExNext(l,fib) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
   {
      if(IsPkt(fib->fib_FileName) || IsArcMail(fib->fib_FileName))
      {
         if(!(tmp=(struct FileToProcess *)AllocMem(sizeof(struct FileToProcess),MEMF_CLEAR)))
         {
            nomem=TRUE;
            break;
         }

         mystrncpy(tmp->Name,fib->fib_FileName,40);
         strcpy(tmp->Comment,fib->fib_Comment);
         tmp->Size=fib->fib_Size;
         CopyMem(&fib->fib_Date,&tmp->Date,sizeof(struct DateStamp));

         if(IsPkt(fib->fib_FileName))
         {
            if(pktlist) jbAddNode(pktlist,(struct jbNode *)tmp);
            else        FreeMem(tmp,sizeof(struct FileToProcess));
         }
         if(IsArcMail(fib->fib_FileName))
         {
            if(arclist) jbAddNode(arclist,(struct jbNode *)tmp);
            else        FreeMem(tmp,sizeof(struct FileToProcess));
         }
      }
      if(strlen(fib->fib_FileName)>4 && stricmp(&fib->fib_FileName[strlen(fib->fib_FileName)-4],".bad")==0)
      {
         LogWrite(1,TOSSINGINFO,"Old bad file found in inbound: %s",fib->fib_FileName);
      }
   }

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      exitprg=TRUE;
}

ScanForNewOldArc(UBYTE *dir,struct jbList *arclist)
{
   BPTR l;
   struct FileInfoBlock *fib;
   struct FileToProcess *tmp;

   jbNewList(arclist);

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      nomem=TRUE;
      return;
   }

   if(!(l=Lock(dir,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Directory \"%s\" not found",dir);
      exitprg=TRUE;
      return;
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Unable to examine lock on \"%s\"",dir);
      exitprg=TRUE;
      return;
   }

   if(fib->fib_DirEntryType <= 0)
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"\"%s\" is a file, not a directory!",dir);
      exitprg=TRUE;
      return;
   }

   while(ExNext(l,fib) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
   {
      UBYTE filename[100];
      strcpy(filename,fib->fib_FileName);

      if(strncmp(filename,"CM_Temp.",8)==0)
      {
         UBYTE oldfilename[100];
         UBYTE oldfull[200];
         UBYTE newfull[200];

         strcpy(oldfilename,filename);
         strcpy(filename,&oldfilename[8]);

         if(IsNewArcMail(filename) || IsArcMail(filename))
         {
            NameFromLock(l,oldfull,199);
            strcpy(newfull,oldfull);

            AddPart(oldfull,oldfilename,199);
            AddPart(newfull,filename,199);

            LogWrite(2,TOSSINGINFO,"Lost renamed bundle found: %s Renaming...",oldfilename);
            Rename(oldfull,newfull);
         }
      }

      if(IsNewArcMail(filename) || IsArcMail(filename))
      {
         if(!(tmp=(struct FileToProcess *)AllocMem(sizeof(struct FileToProcess),MEMF_CLEAR)))
         {
            nomem=TRUE;
            break;
         }

         mystrncpy(tmp->Name,filename,40);
         strcpy(tmp->Comment,fib->fib_Comment);
         tmp->Size=fib->fib_Size;
         CopyMem(&fib->fib_Date,&tmp->Date,sizeof(struct DateStamp));
         jbAddNode(arclist,(struct jbNode *)tmp);
      }
   }

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      exitprg=TRUE;
}

ScanForPktTmp(UBYTE *dir,struct jbList *pktlist)
{
   BPTR l;
   struct FileInfoBlock *fib;
   struct FileToProcess *tmp;

   jbNewList(pktlist);

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      nomem=TRUE;
      return;
   }

   if(!(l=Lock(dir,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Directory \"%s\" not found",dir);
      exitprg=TRUE;
      return;
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Unable to examine lock on \"%s\"",dir);
      exitprg=TRUE;
      return;
   }

   if(fib->fib_DirEntryType <= 0)
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"\"%s\" is a file, not a directory!",dir);
      exitprg=TRUE;
      return;
   }

   while(ExNext(l,fib) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
   {
      if(IsPktTmp(fib->fib_FileName))
      {
         if(!(tmp=(struct FileToProcess *)AllocMem(sizeof(struct FileToProcess),MEMF_CLEAR)))
         {
            nomem=TRUE;
            break;
         }

         mystrncpy(tmp->Name,fib->fib_FileName,40);
         strcpy(tmp->Comment,fib->fib_Comment);
         tmp->Size=fib->fib_Size;
         CopyMem(&fib->fib_Date,&tmp->Date,sizeof(struct DateStamp));
         jbAddNode(pktlist,(struct jbNode *)tmp);
      }
   }

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      exitprg=TRUE;
}

ScanForNewPkt(UBYTE *dir,struct jbList *pktlist)
{
   BPTR l;
   struct FileInfoBlock *fib;
   struct FileToProcess *tmp;

   jbNewList(pktlist);

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      nomem=TRUE;
      return;
   }

   if(!(l=Lock(dir,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Directory \"%s\" not found",dir);
      exitprg=TRUE;
      return;
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"Unable to examine lock on \"%s\"",dir);
      exitprg=TRUE;
      return;
   }

   if(fib->fib_DirEntryType <= 0)
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      LogWrite(1,SYSTEMERR,"\"%s\" is a file, not a directory!",dir);
      exitprg=TRUE;
      return;
   }

   while(ExNext(l,fib) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
   {
      if(IsNewPkt(fib->fib_FileName))
      {
         if(!(tmp=(struct FileToProcess *)AllocMem(sizeof(struct FileToProcess),MEMF_CLEAR)))
         {
            nomem=TRUE;
            break;
         }

         mystrncpy(tmp->Name,fib->fib_FileName,40);
         strcpy(tmp->Comment,fib->fib_Comment);
         tmp->Size=fib->fib_Size;
         CopyMem(&fib->fib_Date,&tmp->Date,sizeof(struct DateStamp));
         jbAddNode(pktlist,(struct jbNode *)tmp);
      }
   }

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      exitprg=TRUE;
}


IsArcMail(UBYTE *file)
{
   UBYTE c;
   UBYTE ext[4];

   if(strlen(file)!=12) return(FALSE);
   if(file[8]!='.')     return(FALSE);

   for(c=0;c<8;c++)
      if((file[c]<'0' || file[c]>'9') && ((file[c]|32) < 'a' || (file[c]|32) > 'f')) return(FALSE);

   strncpy(ext,&file[9],2);
   ext[2]=0;

   if(stricmp(ext,"MO")==0) return(TRUE);
   if(stricmp(ext,"TU")==0) return(TRUE);
   if(stricmp(ext,"WE")==0) return(TRUE);
   if(stricmp(ext,"TH")==0) return(TRUE);
   if(stricmp(ext,"FR")==0) return(TRUE);
   if(stricmp(ext,"SA")==0) return(TRUE);
   if(stricmp(ext,"SU")==0) return(TRUE);

   return(FALSE);
}

IsNewArcMail(UBYTE *file)
{
   UBYTE c;
   UBYTE ext[4];
   UBYTE dots;

   dots=0;
   c=0;

   while(c<strlen(file) && dots!=4)
   {
      if(file[c]=='.')
         dots++;

      else if(file[c]<'0' || file[c]>'9') return(FALSE);

      c++;
   }

   if(dots!=4) return(FALSE);
   if(strlen(&file[c])!=3) return(FALSE);

   strcpy(ext,&file[c]);
   ext[2]=0;

   if(stricmp(ext,"MO")==0) return(TRUE);
   if(stricmp(ext,"TU")==0) return(TRUE);
   if(stricmp(ext,"WE")==0) return(TRUE);
   if(stricmp(ext,"TH")==0) return(TRUE);
   if(stricmp(ext,"FR")==0) return(TRUE);
   if(stricmp(ext,"SA")==0) return(TRUE);
   if(stricmp(ext,"SU")==0) return(TRUE);

   return(FALSE);
}

IsPkt(UBYTE *file)
{
   UBYTE c;

   if(strlen(file)!=12)             return(FALSE);
   if(file[8]!='.')                 return(FALSE);
   if(stricmp(&file[9],"pkt")!=0)   return(FALSE);

   for(c=0;c<8;c++)
      if((file[c]<'0' || file[c]>'9') && ((file[c]|32) < 'a' || (file[c]|32) > 'f')) return(FALSE);

   return(TRUE);
}

IsPktTmp(UBYTE *file)
{
   UBYTE c;

   if(strlen(file)!=15)                return(FALSE);
   if(file[8]!='.')                    return(FALSE);
   if(stricmp(&file[9],"pkttmp")!=0)   return(FALSE);

   for(c=0;c<8;c++)
      if((file[c]<'0' || file[c]>'9') && ((file[c]|32) < 'a' || (file[c]|32) > 'f')) return(FALSE);

   return(TRUE);
}

IsNewPkt(UBYTE *file)
{
   UBYTE c;

   if(strlen(file)!=15)                return(FALSE);
   if(file[8]!='.')                    return(FALSE);
   if(stricmp(&file[9],"newpkt")!=0)   return(FALSE);

   for(c=0;c<8;c++)
      if((file[c]<'0' || file[c]>'9') && ((file[c]|32) < 'a' || (file[c]|32) > 'f')) return(FALSE);

   return(TRUE);
}

DateCompareFTP(struct FileToProcess **f1, struct FileToProcess **f2)
{
   int res;

   res=CompareDates(&(*f1)->Date,&(*f2)->Date);

   if(res<0) return(1);
   if(res>0) return(-1);
   return(0);
}

SortFTPList(struct jbList *list)
{
   struct FileToProcess *ftt,**buf,**work;
   ULONG alloc,nodecount = 0;

   for(ftt=list->First;ftt;ftt=ftt->Next)
      nodecount++;

   if(!nodecount) return;

   if(!(buf=(struct FileToProcess **)AllocMem(nodecount * 4,MEMF_ANY)))
   {
      nomem=TRUE;
      return;
   }
   alloc=nodecount*4;

   work=buf;

   for(ftt=list->First;ftt;ftt=ftt->Next)
      *work++=ftt;

   qsort(buf,nodecount,4,DateCompareFTP);

   jbNewList(list);

   for(work=buf;nodecount--;)
      jbAddNode(list,(struct jbNode *)*work++);

   FreeMem(buf,alloc);
}

strip(UBYTE *str)
{
   int c;
   for(c=strlen(str)-1;str[c] < 33 && c>=0;c--) str[c]=0;
}

#define STATS_IDENTIFIER_OLD  "CST1"
#define STATS_IDENTIFIER      "CST2"

WriteStats()
{
   struct Area *area;
   struct ConfigNode *cnode;
   struct DiskAreaStats dastat;
   struct DiskNodeStats dnstat;
   struct DateStamp ds;
   BPTR fh;
   ULONG areas,nodes;

   DateStamp(&ds);

   if(!(fh=Open(cfg_StatsFile,MODE_NEWFILE)))
   {
      LogWrite(1,SYSTEMERR,"Unable to open %s for writing",cfg_StatsFile);
      return;
   }

   areas=0;
   nodes=0;

   for(area=AreaList.First;area;area=area->Next)
      if(!(area->Flags & AREA_DEFAULT) && !(area->Flags & AREA_UNCONFIRMED))
         areas++;

   for(cnode=CNodeList.First;cnode;cnode=cnode->Next)
      nodes++;

   Write(fh,STATS_IDENTIFIER,4);
   Write(fh,&ds.ds_Days,4);
   Write(fh,&areas,4);

   if(DayStatsWritten == 0)
      DayStatsWritten=ds.ds_Days;

   for(area=AreaList.First;area;area=area->Next)
   {
      if(!(area->Flags & AREA_DEFAULT) && !(area->Flags & AREA_UNCONFIRMED))
      {
         strcpy(dastat.Tagname,area->Tagname);
         dastat.TotalTexts=area->Texts;
         dastat.Dupes=area->Dupes;
         dastat.LastDay=area->LastDay;
         CopyMem(&area->FirstTime,&dastat.FirstTime,sizeof(struct DateStamp));
         CopyMem(&area->Last8Days[0],&dastat.Last8Days[0],8*2);
         Copy4D(&dastat.Aka,&area->Aka->Node);
         dastat.Group=area->Group;

         Write(fh,&dastat,sizeof(struct DiskAreaStats));
      }
   }

   Write(fh,&nodes,4);

   for(cnode=CNodeList.First;cnode;cnode=cnode->Next)
   {
      Copy4D(&dnstat.Node,&cnode->Node);
      dnstat.GotEchomails=cnode->GotEchomails;
      dnstat.GotEchomailBytes=cnode->GotEchomailBytes;
      dnstat.SentEchomails=cnode->SentEchomails;
      dnstat.SentEchomailBytes=cnode->SentEchomailBytes;
      dnstat.GotNetmails=cnode->GotNetmails;
      dnstat.GotNetmailBytes=cnode->GotNetmailBytes;
      dnstat.SentNetmails=cnode->SentNetmails;
      dnstat.SentNetmailBytes=cnode->SentNetmailBytes;
      dnstat.Dupes=cnode->Dupes;
      dnstat.FirstDay=cnode->FirstDay;

      Write(fh,&dnstat,sizeof(struct DiskNodeStats));
   }

   Close(fh);
}

ReadStats()
{
   struct Area *area;
   struct ConfigNode *cnode;
   struct DiskAreaStatsCST1 dastatCST1;
   struct DiskAreaStats dastat;
   struct DiskNodeStats dnstat;
   ULONG c,num;
   BPTR fh;
   UBYTE buf[5];

   DayStatsWritten=0;

   if(!(fh=Open(cfg_StatsFile,MODE_OLDFILE)))
      return;

   Read(fh,buf,4);
   buf[4]=0;

   if(strcmp(buf,STATS_IDENTIFIER)!=0 && strcmp(buf,STATS_IDENTIFIER_OLD)!=0)
   {
      LogWrite(1,SYSTEMERR,"Unknown format of stats file, exiting...");
      Close(fh);
      exitprg=TRUE;
      return;
   }

   if(strcmp(buf,STATS_IDENTIFIER)==0)
   {
      Read(fh,&DayStatsWritten,4);
   }

   Read(fh,&num,4);
   c=0;

   if(strcmp(buf,STATS_IDENTIFIER_OLD)==0)
   {
      while(c<num && Read(fh,&dastatCST1,sizeof(struct DiskAreaStatsCST1))==sizeof(struct DiskAreaStatsCST1))
      {
         for(area=AreaList.First;area;area=area->Next)
            if(stricmp(area->Tagname,dastatCST1.Tagname)==0) break;

         if(area)
         {
            area->Texts=dastatCST1.Texts;
            area->Dupes=dastatCST1.Dupes;
            area->FirstTime.ds_Days=dastatCST1.FirstDay;
         }

         c++;
      }
   }
   else
   {
      while(c<num && Read(fh,&dastat,sizeof(struct DiskAreaStats))==sizeof(struct DiskAreaStats))
      {
         for(area=AreaList.First;area;area=area->Next)
            if(stricmp(area->Tagname,dastat.Tagname)==0) break;

         if(area)
         {
            area->Texts=dastat.TotalTexts;
            area->Dupes=dastat.Dupes;

            CopyMem(&dastat.Last8Days[0],&area->Last8Days[0],8*2);
            CopyMem(&dastat.FirstTime,&area->FirstTime,sizeof(struct DateStamp));
            area->LastDay=dastat.LastDay;
         }
         c++;
      }
   }

   Read(fh,&num,4);
   c=0;

   while(c<num && Read(fh,&dnstat,sizeof(struct DiskNodeStats))==sizeof(struct DiskNodeStats))
   {
      for(cnode=CNodeList.First;cnode;cnode=cnode->Next)
         if(Compare4D(&dnstat.Node,&cnode->Node)==0) break;

      if(cnode)
      {
         cnode->GotEchomails=dnstat.GotEchomails;
         cnode->GotEchomailBytes=dnstat.GotEchomailBytes;
         cnode->SentEchomails=dnstat.SentEchomails;
         cnode->SentEchomailBytes=dnstat.SentEchomailBytes;
         cnode->GotNetmails=dnstat.GotNetmails;
         cnode->GotNetmailBytes=dnstat.GotNetmailBytes;
         cnode->SentNetmails=dnstat.SentNetmails;
         cnode->SentNetmailBytes=dnstat.SentNetmailBytes;
         cnode->Dupes=dnstat.Dupes;

         cnode->FirstDay=dnstat.FirstDay;
      }

      c++;
   }

   Close(fh);
}

AddChunkList(struct jbList *chunklist,UBYTE *buf,ULONG buflen)
{
   ULONG left,copy,pos;
   struct TextChunk *chunk;

   chunk=chunklist->Last;

   if(chunk==NULL)
   {
      if(!(chunk=(struct TextChunk *)AllocMem(sizeof(struct TextChunk),MEMF_ANY)))
      {
         nomem=TRUE;
         return;
      }
      chunk->Length=0;
      jbAddNode(chunklist,(struct jbNode *)chunk);
   }

   if(chunk->Length==PKT_CHUNKLEN)
   {
      if(!(chunk=(struct TextChunk *)AllocMem(sizeof(struct TextChunk),MEMF_ANY)))
      {
         nomem=TRUE;
         return;
      }
      chunk->Length=0;
      jbAddNode(chunklist,(struct jbNode *)chunk);
   }

   left=buflen;
   pos=0;

   while(left)
   {
      if(left < PKT_CHUNKLEN-chunk->Length) copy=left;
      else                                  copy=PKT_CHUNKLEN-chunk->Length;

      CopyMem(&buf[pos],&chunk->Data[chunk->Length],copy);
      chunk->Length+=copy;

      left-=copy;
      pos+=copy;

      if(left)
      {
         if(!(chunk=(struct TextChunk *)AllocMem(sizeof(struct TextChunk),MEMF_ANY)))
         {
            nomem=TRUE;
            return;
         }
         chunk->Length=0;
         jbAddNode(chunklist,(struct jbNode *)chunk);
      }
   }
}

MakeFidoDate(struct DateStamp *ds,UBYTE *dest)
{
   struct DateTime dt;
   UBYTE date[40],time[40];

   CopyMem(ds,&dt.dat_Stamp,sizeof(struct DateStamp));

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

   date[2]=0;
   date[5]=0;

   sprintf(dest,"%s %s %s  %s",date,MonthNames[atoi(&date[3])-1],&date[6],time);
}


MakeNetmailKludges(struct jbList *chunklist,struct Node4D *orig,struct Node4D *dest,ULONG addtid)
{
   /* workaround!!! BOOL is only int... */

   UBYTE buf[100];

   if(orig->Point)
   {
      sprintf(buf,"\x01FMPT %lu\x0d",orig->Point);
      AddChunkList(chunklist,buf,strlen(buf));
   }
   if(dest->Point)
   {
      sprintf(buf,"\x01TOPT %lu\x0d",dest->Point);
      AddChunkList(chunklist,buf,strlen(buf));
   }
   if(orig->Zone != dest->Zone || cfg_Flags & CFG_FORCEINTL)
   {
      sprintf(buf,"\x01INTL %lu:%lu/%lu %lu:%lu/%lu\x0d",dest->Zone,dest->Net,dest->Node,
                                                   orig->Zone,orig->Net,orig->Node);
      AddChunkList(chunklist,buf,strlen(buf));
   }

   if(addtid)
   {
      if(Checksum11() != checksums[11])
         strcpy(buf,"\x01TID: CrashMail "TID_VERSION" Unreg\x0d");

      else
         sprintf(buf,"\x01TID: CrashMail "TID_VERSION" %lu\x0d",key.Serial);

      AddChunkList(chunklist,buf,strlen(buf));
   }
}

SafeDelete(UBYTE *file)
{
   struct FileToProcess *ftp;

   if(!(ftp=AllocMem(sizeof(struct FileToProcess),MEMF_ANY)))
   {
      nomem=TRUE;
      return;
   }

   strcpy(ftp->Name,file);
   jbAddNode(&DeleteList,(struct jbNode *)ftp);
}

GetCharset(UBYTE *string,UBYTE *defchrs)
{
   struct CharsetAlias *charsetalias;

   if(strncmp(string,"IBMPC",5)==0)
      return(IbmToAmiga);

   else if(strncmp(string,"SWEDISH",7)==0)
      return(SF7ToAmiga);

   else if(strncmp(string,"MAC",3)==0)
      return(MacToAmiga);

   else if(strncmp(string,"LATIN-1",7)!=0)
   {
      for(charsetalias=CharsetList.First;charsetalias;charsetalias=charsetalias->Next)
         if(strcmp(string,charsetalias->Name)==0)
         {
            LogWrite(5,TOSSINGINFO,"Non-standard charset %s, using %s",string,charsetalias->AliasName);
            return(charsetalias->CHRS);
         }

      if(string[0]!=0)
      {
         LogWrite(3,TOSSINGINFO,"Unknown charset %s",string);
      }

      return(defchrs);
   }

   return(NULL);
}

struct Aka *GetRouteAka(struct Node4D *node)
{
   struct Route *tmproute;

   for(tmproute=RouteList.First;tmproute;tmproute=tmproute->Next)
      if(Compare4DPat(&tmproute->Pattern,node)==0) return(tmproute->Aka);

   return(NULL);
}


void mystrncpy(char *dest,char *src,long len)
{
   strncpy(dest,src,len-1);
   dest[len-1]=0;
}
