#include "zbun.h"
#include "ivn.h"

#include <link/io.h>

/* this program's job is to find ????????.pkt files and turn them into
   either .?UT files or bundles */

struct   Library    *DLGBase = NULL;

struct   FileInfoBlock *FIB1=NULL;

BPTR  fl1=NULL;
BPTR  fl3=NULL;
BPTR  fh2=NULL;
BPTR  fh3=NULL;
BPTR  sout;

char logstring[1000];

struct GConfig *GCFG;

char far PKTNAMES[MAXPKTS][50];
char far *pktn[MAXPKTS];

BPTR nilfh=NULL;

BOOL MADECRASH=FALSE;

long  __stack = 100000L;

// --------------------------------------------

int   CheckDLGMAILSTOP(void);
void  QuietExit(void);
int   GetPkts(void);

// --------------------------------------------

/// Main
int main(int argc, char **argv)
{
   char curname[100];
   char curdest[100];
   char bundleto[100];
   char archiverstring[100];

   ULONG type;
   ULONG newtype;
   ULONG killtype;
   ULONG flavor;

   int tot,ii;

   sout = Output();

/// Open dlg.library
   DLGBase = OpenLibrary("dlg.library",4L);

   if(!DLGBase) exit(20);
//-

   printf("%s\n\n",ID_STRING);

   if(argc!=2) exit(20);

/// Global Config
   GCFG=NULL;

   if(!Stricmp(argv[1],"NEW"))
   {
      FILE *fp;
      char buf[20];

      if(fp=fopen("ENV:GCFG","r"))
      {
         fgets(buf,16,fp);
         fclose(fp);
         GCFG=(struct GConfig *)atoi(buf);
      }
   }
   else
   {
      GCFG=(struct GConfig *)atoi(argv[1]);
   }

   if(GCFG==NULL)
   {
      printf("No GCFG - Exiting\n");
      exit(20);
   }

   if((GCFG->MARKER1 != 5551212) || (GCFG->MARKER2 != 5551212))
   {
      printf("ERROR: GCFG Marker Failure\n");
      exit(20);
   }
//-

/// Open NULL:
   nilfh=Open("NULL:",MODE_NEWFILE);

   if(!nilfh)
   {
      printf("No NULL: fh\n");
      Log("! No NULL: fh\n");
      exit(20);
   }
//-

   SetZTaskPri();

   sprintf(logstring,"== %s",ID_STRING);
   Log(logstring);

/// Allocate FIB
   FIB1 = AllocDosObject(DOS_FIB,TAG_END);

   if(FIB1 == NULL)
      QuietExit();
//-

   tot=GetPkts();

/// Process packets, if any
   if(tot > 0)
   {
      if(_LOG>TALKATIVE) Log("|*--- Processing packets...");

      for(ii=0;ii<tot;ii++)
      {
         if(CheckDLGMAILSTOP())
            break;

         sprintf(curname,"%12.12s",pktn[ii]);
         sprintf(curdest,"%s",pktn[ii]+13);

         if(_LOG>TALKATIVE)
         {
            sprintf(logstring,"... Found [%s] to [%s]",curname,curdest);
            Log(logstring);
         }

         BundleCommand(curdest,bundleto,archiverstring,&type);

         sprintf(logstring,"... Routing [%s] via [%s], type [%d]",bundleto,archiverstring,type);
         Log(logstring);

         printf("(%3d of %d): [[32m%s[0m] for [[33m%s[0m] routed thru [[33m%s[0m]\n",ii+1,tot,curname,curdest,bundleto);

         if(type&flavor_CRASH)
            MADECRASH=TRUE;

         if(type&flavor_BUNDLE)
         {
            if(type&flavor_DIRECT)
            {
               if(_LOG>TALKATIVE) Log("... Bundle DIRECT");
            }
            if(type&flavor_CRASH)
            {

               if(_LOG>TALKATIVE) Log("... Bundle CRASH");
            }
            if(type&flavor_NORMAL)
            {
               if(_LOG>TALKATIVE) Log("... Bundle NORMAL");
            }
            if(type&flavor_HOLD)
            {
               if(_LOG>TALKATIVE) Log("... Bundle HOLD");
            }
         }

         if(type&flavor_BUNDLE)
         {
            flavor=type;
            flavor&=(flavor_CRASH | flavor_NORMAL | flavor_DIRECT | flavor_HOLD);
            type=type&(0xffff ^ flavor_CRASH ^ flavor_NORMAL ^ flavor_DIRECT ^ flavor_HOLD);

            HuntFor(bundleto,type,&newtype,&killtype);

            if(newtype & flavor_BUNDLE)  AddToABundle(curname,bundleto,archiverstring,newtype,killtype,flavor);
         }
         else
         {
            Log("... No bundling... Treating as a packet");
            AddToOldPKT(curname,bundleto,type);
         }
      }
   }
   else
   {
      Log(". No .PKT's to process...");
   }
//-

   if(_LOG>TALKATIVE) Log("== Done looking for .PKT's");
   
   QuietExit();
}
//-

/// GetPkts
int GetPkts(void)
{
   int i;
   int j;
   /*char *pkts[100];*/
   int type;
   char *filename;
   char *filenote;
   BPTR LockFile;

   if(_LOG>TALKATIVE)
   {
      sprintf(logstring,"---- Begin GetPkts()");
      Log(logstring);
   }

   LockFile=Lock("OUTBOUND:",ACCESS_READ);

   if(LockFile)
   {
      i=Examine(LockFile, FIB1);

      if(i)
      {
         j=0;

         while(j<(MAXPKTS-1))
         {
            type=FIB1->fib_DirEntryType;
            filename=FIB1->fib_FileName;
            filenote=FIB1->fib_Comment;

            Upper(filename);

            if(type<0 && (12==stcpma(filename,"????????.PKT")) && *filenote) /* if the filenote is NULL, don't process */
            {
               sprintf(PKTNAMES[j],"%12.12s %s",filename,filenote);

               pktn[j]=PKTNAMES[j];
               j++;
            }

            i=ExNext(LockFile,FIB1);

            if(!i) break;
         }

         if(j>0)
         {
            if(_LOG>TALKATIVE) printf("\nThere are %d outbound .PKT's - Sorting\n",j);
            tqsort(pktn,j);
         }
         else
         {
            if(_LOG>TALKATIVE) printf("No .PKT's to process\n");
         }
      }

      UnLock(LockFile);

      if(_LOG>TALKATIVE)
      {
         sprintf(logstring,"==== End GetPkts()");
         Log(logstring);
      }

      return(j);
   }
   else
   {
      sprintf(logstring,"   ! ERROR: Can't lock OUTBOUND:, ending GetPkts()");
      Log(logstring);
      printf("Can't get a lock on OUTBOUND: to get a directory of .PKT's\n");
      return(-100);
   }
}
//-

/// BundleCommand
int BundleCommand(char *curdest,char *bundleto,char *archiverstring,ULONG *type)
{
   FILE *fp;

   BOOL breakflag;

   char buffer[250];
   char buf[100];
   char key[100];
   char *s,*p;

   /* defaults if no control file */

   strcpy(bundleto,curdest);
   strcpy(archiverstring,_ARCADD);
   *type=0;

   fp=fopen("FIDO:DLGMail.BUN","r");

   if(fp)
   {
      breakflag=FALSE;

      while(1)
      {
         if(NULL==fgets(buffer,248,fp)) break;

         if(strlen(buffer)>0) buffer[strlen(buffer)-1]=NULL;

         if(buffer[0]==';' || buffer[0]==NULL) continue; /* skip comments */

         p=buffer;
         s=p;
         p=stptok(s,buf,sizeof(buf)," \t");


         if(!FidoPatternMatch(curdest,buf)) continue;

         /* we found our entry, now parse the line for info */
         breakflag=TRUE;

         while(1)
         {        
            s=stpblk(p);
            if(p==s) break;   /* end of string */
            p=s;
            if(*p==';') break; /* comment follows */
            p=stptok(s,key,sizeof(key)," \t");
            /* key holds keyword */
            s=stpblk(p);
            if(p==s) break;   /* end of string */
            p=s;
            p=stptok(s,buf,sizeof(buf)," \t");
            
            if(!Stricmp(key,"THROUGH") || !Stricmp(key,"THRU"))
            {
               strcpy(bundleto,buf);
            }

            if(!Stricmp(key,"ARCHIVER"))
            {
               if(!Stricmp(buf,"ARC"))  {strcpy(archiverstring,_ARCADD );*type|=flavor_BUNDLE;}
               if(!Stricmp(buf,"ZOO"))  {strcpy(archiverstring,_ZOOADD );*type|=flavor_BUNDLE;}
               if(!Stricmp(buf,"LZH"))  {strcpy(archiverstring,_LZHADD );*type|=flavor_BUNDLE;}
               if(!Stricmp(buf,"LHA"))  {strcpy(archiverstring,_LHAADD );*type|=flavor_BUNDLE;}
               if(!Stricmp(buf,"ZIP"))  {strcpy(archiverstring,_ZIPADD );*type|=flavor_BUNDLE;}
               if(!Stricmp(buf,"ARJ"))  {strcpy(archiverstring,_ARJADD );*type|=flavor_BUNDLE;}
               if(!Stricmp(buf,"NONE"))    {strcpy(archiverstring,"");*type|=flavor_PKTFILE;}
            }

            if(!Stricmp(key,"TYPE"))
            {
               if(!Stricmp(buf,"CRASH"))   *type|=flavor_CRASH;
               if(!Stricmp(buf,"NORMAL"))  *type|=flavor_NORMAL;
               if(!Stricmp(buf,"DIRECT"))  *type|=flavor_DIRECT;
               if(!Stricmp(buf,"HOLD"))    *type|=flavor_HOLD;
            }
         }
         if(breakflag) break;
      }
      fclose(fp);
   }

   if(((*type&flavor_BUNDLE)==0) && ((*type&flavor_PKTFILE)==0))
      *type |= flavor_BUNDLE;

   if(((*type&flavor_CRASH)==0) && ((*type&flavor_NORMAL)==0) && ((*type&flavor_DIRECT)==0) && ((*type&flavor_HOLD)==0))   
      *type |= flavor_DIRECT;

   if(*type&flavor_BUNDLE)
      *type |= BundleToday();

   return(0);
}
//-

/// BundleToday
int BundleToday(void)
{
   int i;
   unsigned char clock[10];

   getclk(clock);

   i=clock[0]+8;

   return(1<<i);
}
//-

/// HuntFor
int HuntFor(char *bundleto,ULONG itstype, ULONG *newtype, ULONG *killtype)
{
   int rc,oldlength;

   int izone=0;
   int inet=0;
   int inode=0;
   int ipoint=0;

   ULONG type=0;
   ULONG oldtype=0;

   char huntfor[100];
   char *oldname;

   char string[100];

   BPTR fh;

   BOOL flag=FALSE;

   struct FileInfoBlock *myfib;

   BOOL verifywritability=FALSE;

   *newtype=0;
   *killtype=0;

   myfib= AllocDosObject(DOS_FIB,TAG_END);

   if(myfib)
   {
      if(itstype & flavor_BUNDLE)   type=flavor_BUNDLE|flavor_ANY;
      if(itstype & flavor_PKTFILE)  type=flavor_PKTFILE|flavor_ANY;
      if(itstype & flavor_FLOWFILE) type=flavor_FLOWFILE|flavor_ANY;

      AddToWild(bundleto,huntfor,type);
   
      fh=Lock("OUTBOUND:",ACCESS_READ);

      if(fh)
      {
         if(Examine(fh,myfib))
         {
            while(1)
            {
               rc=0;

               if(FALSE==ExNext(fh,myfib)) break;

               oldname=myfib->fib_FileName;
               strupr(oldname);
               oldlength=myfib->fib_Size;

               if(FidoPatternMatch(oldname,huntfor))
               {
                  flag=TRUE;
                  EvaluateFilename(oldname,NULL,&izone,&inet,&inode,&ipoint,&oldtype);

                  if((itstype & flavor_PKTFILE) && (oldtype & flavor_PKTFILE))
                  {
                     *newtype=oldtype; /*this, in effect, will add the new packet to any old packet wthout regard for flavor */
                     rc=1;
                  }

                  if((itstype & flavor_BUNDLE) && (oldtype & flavor_BUNDLE) && oldlength)
                  {
                     *newtype=oldtype;
                     verifywritability=TRUE;
                     sprintf(string,"OUTBOUND:%s",oldname);
                     rc=1;
                  }

                  if((itstype & flavor_BUNDLE) && (oldtype & flavor_BUNDLE) && oldlength==0)
                  {
/*======> */                  if(oldtype & BundleToday())
                        *newtype=oldtype+1; /* here's where we can fix */
                     else
                        *newtype=itstype;
                     *killtype=oldtype;
                     rc=1;
                  }

                  if((itstype & flavor_FLOWFILE) && (oldtype & flavor_FLOWFILE))
                  {
                     *newtype=oldtype;
                     rc=1;
                  }
                  if(rc) break;
               }
            }
         }
         UnLock(fh);
      }
      FreeDosObject(DOS_FIB,myfib);
   }

   if(verifywritability)
   {
      fh=Lock(string,ACCESS_WRITE);

      if(fh)
         UnLock(fh);
      else
      {     
         /* magic goes here */

         *newtype=oldtype+1;
      }
   }

   if(*newtype==0)
   {
      *newtype=itstype;
   }
   return(rc);
}
//-

/// AddToOldPKT
int AddToOldPKT(char *curname,char *bundleto,ULONG newtype)
{
   char newname[100];
   char nn[100];
   char on[100];
   char copybuf[1000];

   int c;

   ULONG ntype;

   if(_LOG>TALKATIVE) Log("--- Adding to packet");
   ntype=newtype;
   sprintf(on,"OUTBOUND:%s",curname);
   AddToWild(bundleto,newname,ntype);
   sprintf(nn,"OUTBOUND:%s",newname);

   fh2=Open(nn,MODE_OLDFILE);

   if(fh2)
   {
      if(_LOG>TALKATIVE) printf("Appending [[32m%s[0m]\n",on);
      if(_LOG>TALKATIVE) printf("to packet [[32m%s[0m]... ",nn);

      if(_LOG>TALKATIVE)
      {
         sprintf(logstring,"... Appending %s to packet %s",on,nn);
         Log(logstring);
      }


      Seek(fh2,0,OFFSET_BEGINNING);
      Seek(fh2,-2,OFFSET_END); /* this may have to be diddled */

      fh3=Open(on,MODE_OLDFILE);

      if(fh3)
      {
         Seek(fh3,0,OFFSET_BEGINNING);
         Seek(fh3,sizeof(struct Packet_Header),OFFSET_BEGINNING); /* this may have to be diddled */

         while(1)
         {
            c=Read(fh3,copybuf,999);
            Write(fh2,copybuf,c);
            if(c!=999) break;
         }

         Close(fh3);
         fh3=NULL;
         DeleteFile(on);
         printf("\n");
      }
      else
      {
         Log("  ! Strange, can't open source packet");
         printf("Strange, can't open %s\n",on);
      }

      Close(fh2);
      fh2=NULL;
   }
   else
   {
      /* we need to rename the .pkt to the full new address here */
      AddToWild(bundleto,newname,ntype);
      if(_LOG>TALKATIVE) printf("    Renaming [[32m%s[0m]\n",curname);
      if(_LOG>TALKATIVE) printf("          to [[32m%s[0m]... ",newname);

      sprintf(logstring,"... Renaming %s to %s to make new destination packet",curname,newname);
      Log(logstring);

      if(RenameOutbound(curname,newname))
      {
         if(_LOG>ANNOYING) printf("Done with entry\n");
      }
      else
      {
         printf("Problem, can't rename ?!?!\n");
         Log("  ! Problem, can't rename packet...");
      }
   }

   printf("[0m");

   if(_LOG>TALKATIVE) Log("=== Done adding to packet");

   return(0);
}
//-

/// AddToABundle
int AddToABundle(char *curname,char *bundleto,char *archiverstring,ULONG newtype,ULONG killtype,ULONG flavor)
{
   /* this routine ought to use fork, let ross fix that part */

   FILE *fp;

   ULONG returntype,nonsense;

   char buffer[200];

   BOOL flag;
   char exstring[200];
   char bundlename[100];
   char flowbundlename[100];

   char flowstring[100];

   if(_LOG>TALKATIVE) Log("-- Adding to a bundle");

   AddToWild(bundleto,bundlename,newtype);

   sprintf(exstring,archiverstring,bundlename,curname);

   if(_LOG>TALKATIVE)
   {
      printf("     Adding packet [[32m%s[0m]\n",curname);
      printf("         to bundle [[32m%s[0m]...\n[30m",bundlename);
      sprintf(logstring,".. Moving packet %s to bundle %s",curname,bundlename);
      Log(logstring);
   }

   if(!Spawn(nilfh,nilfh, exstring))
   {
      sprintf(exstring,"OUTBOUND:%s",curname);
      DeleteFile(exstring);
   }
   else
   {
      Log(".. archiver failed!");
   }

   printf("[0m");
   sprintf(exstring,"OUTBOUND:%s",bundlename);
   SetComment(exstring,bundleto);
   sprintf(flowbundlename,"#Outbound:%s",bundlename);

   if(killtype)
   {
      AddToWild(bundleto,bundlename,killtype);
      sprintf(exstring,"OUTBOUND:%s",bundlename);

      if(_LOG>VERBOSE) printf("Killing old bundle [[32m%s[0m]...\n",bundlename);

      if(_LOG>TALKATIVE)
      {
         sprintf(logstring,"... Killing old truncated bundle %s",bundlename);
         Log(logstring);
      }

      DeleteFile(exstring);
   }

   /* flowbundlename is what we have to make sure exists inside
      a flow file */

   Upper(flowbundlename);

   HuntFor(bundleto,(flavor_FLOWFILE|flavor),&returntype,&nonsense);
   AddToWild(bundleto,flowstring,returntype);

   sprintf(exstring,"OUTBOUND:%s",flowstring);

   fl3=Lock(exstring,ACCESS_READ);

   if(fl3)
   {
      UnLock(fl3);
      fl3=NULL;

      if(_LOG>VERBOSE) printf("Flowfile [[32m%s[0m] Exists...\n",flowstring);

      /* there's already a flow file - let's see if our entry
         already exists */

      fp=fopen(exstring,"r");

      if(fp)
      {
         flag=FALSE;

         while(1)
         {
            if(NULL==fgets(buffer,198,fp)) break;

            buffer[strlen(buffer)-1]=NULL;   /*strip newline*/
            Upper(buffer);

            if(!Stricmp(buffer,flowbundlename))
            {
               flag=TRUE;

               if(_LOG>VERBOSE) printf("Bundle Entry [[32m%s[0m] Exists...\n",flowbundlename);

               if(_LOG>TALKATIVE)
               {
                  sprintf(logstring," ! Bundle entry %s already exists in flowfile %s",flowbundlename,flowstring);
                  Log(logstring);
               }

               break;
            }
         }
         fclose(fp);

         if(flag==FALSE)
         {
            AppendFlowFile(exstring,flowbundlename);

            if(_LOG>TALKATIVE)
            {
               sprintf(logstring,".. Adding to existing flowfile %s for %s",flowstring,flowbundlename);
               Log(logstring);
            }
         }
      }
   }
   else
   {
      if(_LOG>TALKATIVE)
      {
         printf("Creating New Flowfile [[32m%s[0m]...\n",flowstring);
         sprintf(logstring,".. Creating new flowfile %s for %s",flowstring,flowbundlename);
         Log(logstring);
      }

      AppendFlowFile(exstring,flowbundlename);
   }

   if(_LOG>ANNOYING) printf("Done with entry\n");

   if(_LOG>TALKATIVE) Log("== Done adding to a bundle");

   return(0);
}
//-

/// AppendFlowFile
int AppendFlowFile(char *name,char *entry)
{
   FILE *fp;

   if(_LOG>TALKATIVE) printf("Adding Entry [[32m%s[0m]...\n",entry);

   fp=fopen(name,"a");

   if(fp)
   {
      fprintf(fp,"%s\n",entry);
      fclose(fp);
   }
   else
   {
      sprintf(logstring,"  ! Couldn't open %s to create new flowfile",name);
      Log(logstring);
      printf("Couldn't open [%s] to create new flowfile\n",name);
   }

   return(0);
}
//-

/// SetZTaskPri
SetZTaskPri()
{
   struct Task *MyTask;

   MyTask=(struct Task *)FindTask(NULL);

   if(_ZTASKPRI)
   {
      SetTaskPri(MyTask,_ZTASKPRI);
   }

   return(0);
}
//-

/// ParseArgs
#define MAX_ARGS 20

int ParseArgs(char **argv,char *argstring)
{
   char token[100];
   char *s;
   int i=0;

   s=argstring;

   argv[i]=NULL;

   while(*s != NULL && i<MAX_ARGS)
   {
      s=stpblk(s);

      if(*s)
      {
         argv[i]=s;
         i++;
         argv[i]=NULL;
         s=stptok(s,token,sizeof(token)," \t");
         if(*s) *s++=NULL;
      }
   }
   return(i);
}
//-

/// CheckDLGMMAILSTOP
int CheckDLGMAILSTOP(void)
{
   if(Exists("ENV:DLGMAILSTOP"))
   {
      Log(". DLGMail told me to stop bundling");
      return(1);
   }
   else
      return(0);
}
//-

/// QuietExit
void QuietExit(void)
{
   if(fl1) UnLock(fl1);
   if(fl3) UnLock(fl3);

   if(fh2) UnLock(fh2);
   if(fh3) UnLock(fh3);

   if(FIB1) FreeDosObject(DOS_FIB,FIB1);

   Log("= DLGBundle Complete\n");

   if(nilfh) Close(nilfh);

   if(DLGBase) CloseLibrary(DLGBase);

   _RETURNCODE=0;

   if(MADECRASH) _RETURNCODE |= ACT_CRASH;

   exit(0);
}
//-

