#include <CrashMail.h>

Compare(UBYTE *str, UBYTE *recog)
{
   ULONG c,d;
   UBYTE comp;
   UBYTE buf[5];

   d=0;

   for(c=0;d<strlen(recog);c++)
   {
      if(recog[d]=='$')
      {
         strncpy(buf,&recog[d+1],2);
         buf[2]=0;
         comp=HexToDec(buf);
         if(str[c]!=comp) return(FALSE);
         d+=3;
      }
      else
      {
         if(str[c]!=recog[d] && recog[d]!='?') return(FALSE);
         d++;
      }
   }

   return(TRUE);
}

HexToDec(char *hex)
{
   char *hextab="0123456789abcdef";
   int c=0,c2=0;
   unsigned long result=0;

   while(hex[c])
   {
      hex[c]|=32;

      for(c2=0;c2<16;c2++)
      {
         if(hex[c] == hextab[c2])
         {
            result *= 16;
            result += c2;
         }
      }
      c++;
   }
   return(result);
}

ExaminePacker(UBYTE *name)
{
   BPTR fh;
   UBYTE buf[40];
   struct Packer *tmppacker;

   if(!(fh=Open(name,MODE_OLDFILE)))
   {
      LogWrite(1,SYSTEMERR,"Unable to open %s",FilePart(name));
      return(NULL);
   }

   Read(fh,buf,40);
   Close(fh);

   for(tmppacker=PackerList.First;tmppacker;tmppacker=tmppacker->Next)
      if(Compare(buf,tmppacker->Recog)) return(tmppacker);

   LogWrite(1,TOSSINGERR,"Unknown packer for %s",FilePart(name));
   SetComment(name,"Unknown packer");
   return(NULL);
}

void LogTossResults(void)
{
   struct Area *area;

   PutStr("                              \n");
   PutStr("\n");

   for(area=AreaList.First;area;area=area->Next)
   {
      if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
         return;

      if(!diskfull && !nomem && !exitprg)
      {
         if(area->NewDupes)
            LogWrite(3,TOSSINGINFO,"Area %s -- %lu messages (%lu dupes)",area->Tagname,area->NewTexts,area->NewDupes);

         else if(area->NewTexts)
            LogWrite(3,TOSSINGINFO,"Area %s -- %lu messages",area->Tagname,area->NewTexts);
      }
   }

   PutStr("\n");

   LogWrite(1,TOSSINGINFO,"   Total ->     Read messages: %6lu     Written messages: %6lu",toss_total,toss_written);
   LogWrite(1,TOSSINGINFO,"Imported -> Imported messages: %6lu      Routed netmails: %6lu",toss_import,toss_route);
   LogWrite(1,TOSSINGINFO,"     Bad ->      Bad messages: %6lu   Duplicate messages: %6lu",toss_bad,toss_dupes);

   PutStr("\n");
}

BOOL Toss(void)
{
   struct FileToProcess    *tmp;
   struct jbList           PktTPList;
   struct jbList           ArcTPList;
   UBYTE buf[100];

   LogWrite(3,ACTIONINFO,"Tossing...");

   isscanning=FALSE;
   isrescanning=FALSE;

   if(!InitSession())
      return(FALSE);

   ScanForPktArcShowBad(cfg_Inbound,&PktTPList,&ArcTPList);
   SortFTPList(&PktTPList);
   SortFTPList(&ArcTPList);

   if(nomem || exitprg)
   {
      jbFreeList(&PktTPList,PktTPList.First,sizeof(struct FileToProcess));
      jbFreeList(&ArcTPList,ArcTPList.First,sizeof(struct FileToProcess));
      return(FALSE);
   }

   for(tmp=PktTPList.First;tmp;tmp=tmp->Next)
   {
      strcpy(buf,cfg_Inbound);
      AddPart(buf,tmp->Name,100);

      if(stricmp(tmp->Comment,"No security")==0)
         no_security=TRUE;

      ReadPkt(buf,tmp->Size);

      no_security=FALSE;

      if(nomem || exitprg || diskfull)
      {
         jbFreeList(&PktTPList,PktTPList.First,sizeof(struct FileToProcess));
         jbFreeList(&ArcTPList,ArcTPList.First,sizeof(struct FileToProcess));
         return(FALSE);
      }
      SafeDelete(buf);
   }

   jbFreeList(&PktTPList,PktTPList.First,sizeof(struct FileToProcess));

   for(tmp=ArcTPList.First;tmp && !exitprg && !diskfull && !nomem;tmp=tmp->Next)
   {
      strcpy(buf,cfg_Inbound);
      AddPart(buf,tmp->Name,100);

      TossBundle(buf,tmp->Size);

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

   jbFreeList(&ArcTPList,ArcTPList.First,sizeof(struct FileToProcess));

   ClosePackets(); /* Close in advance to be on the safe side */

   if(!diskfull && !nomem && !exitprg)
      LogTossResults();

   FinishSession();

   return(TRUE);
}

BOOL TossBundle(UBYTE *file,ULONG size)
{
   BPTR l,oldl;
   struct Packer *tmppacker;
   struct FileToProcess *safedel;
   UBYTE buf[100],buf2[100];
   ULONG arcres;
   struct jbList PktTPList;
   struct FileToProcess *tmp2;

   if(size == 0)
   {
      LogWrite(1,TOSSINGINFO,"Deleting zero length bundle %s",FilePart(file));
      DeleteFile(file);
      return(TRUE);
   }

   if(!(l=Lock(cfg_TempDir,SHARED_LOCK)))
   {
      LogWrite(1,SYSTEMERR,"Unable to lock temp directory \"%s\"",cfg_TempDir);     
      exitprg=TRUE;
      return(FALSE);
   }

   if(tmppacker=(struct Packer *)ExaminePacker(file))
   {
      LogWrite(2,TOSSINGINFO,"Unarchiving %s using %s",FilePart(file),tmppacker->Name);           

      ExpandPacker(tmppacker->Unpacker,buf2,file,"");

      oldl=CurrentDir(l);
      PutStr("\n");
      arcres=SystemTags(buf2,TAG_DONE);
      PutStr("\n");
      CurrentDir(oldl);

      SetSignal(0L,SIGBREAKF_CTRL_C);

      if(arcres!=0)
      {
         LogWrite(1,SYSTEMERR,"Unarchiving failed: %lu",arcres);
         LogWrite(3,TOSSINGERR,"Renaming %s to .bad",FilePart(file));

         strcpy(buf,file);
         strcat(buf,".bad");
         Rename(file,buf);
         sprintf(buf2,"Unarchiving with %s failed: %lu",tmppacker->Name,arcres);
         SetComment(buf,buf2);
     }

      ScanForPktArc(cfg_TempDir,&PktTPList,NULL);
      SortFTPList(&PktTPList);

      if(nomem || exitprg)
      {
         UnLock(l);
         jbFreeList(&PktTPList,PktTPList.First,sizeof(struct FileToProcess));
         return(FALSE);
      }

      for(tmp2=PktTPList.First;tmp2 && !exitprg;tmp2=tmp2->Next)
      {
         strcpy(buf,cfg_TempDir);
         AddPart(buf,tmp2->Name,100);

         /* If you have your tempdir in Inbound, this might be an unpacked
            mailpacket that has been processed already */

         for(safedel=DeleteList.First;safedel;safedel=safedel->Next)
            if(strcmp(safedel->Name,buf)==0) break;

         if(!safedel)
            ReadPkt(buf,tmp2->Size);

         if(nomem || exitprg || diskfull)
         {
            UnLock(l);
            jbFreeList(&PktTPList,PktTPList.First,sizeof(struct FileToProcess));
            return(FALSE);
         }
         DeleteFile(buf);

         if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
            exitprg=TRUE;
      }
      jbFreeList(&PktTPList,PktTPList.First,sizeof(struct FileToProcess));

      if(arcres==0)
      {
         SafeDelete(file);
      }
   }

   UnLock(l);

   if(tmppacker) return(TRUE);
   else          return(FALSE);
}

BOOL TossFile(UBYTE *file)
{
   struct FileInfoBlock *fib;
   BPTR l;
   ULONG size;
   UBYTE Comment[200];

   isscanning=FALSE;
   isrescanning=FALSE;

   if(!InitSession())
      return(FALSE);

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

   if(!(l=Lock(file,SHARED_LOCK)))
   {
      LogWrite(1,USERERR,"Unable to open %s",file);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return(FALSE);
   }

   Examine(l,fib);

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

   size=fib->fib_Size;
   strcpy(Comment,fib->fib_Comment);

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

   if(IsPkt(FilePart(file)))
   {
      if(stricmp(Comment,"No security")==0)
         no_security=TRUE;

      ReadPkt(file,size);

      no_security=FALSE;

      if(!nomem && !exitprg && !diskfull)
         SafeDelete(file);
   }
   else
   {
      if(!TossBundle(file,size))
      {
         return(FALSE);
      }
   }

   if(!nomem && !exitprg && !diskfull)
      LogTossResults();

   FinishSession();

   return(TRUE);
}

