#include "zmiglobals.h"

#include <link/io.h>
#include <link/util.h>

void DeleteWM(char *,long,int);


char far REMEMBERAREA[MAXEXPAREAS][30];
int far REMEMBERAREALOW[MAXEXPAREAS];
int far REMEMBEREXPTALLY[MAXEXPAREAS];
int far totREMEMBEREXP;

int NULLMSGS=0;

#define DB2 1

#define NO_ERROR  0
#define OUT_OF_MEMORY   1<<0
#define FILE_ERROR   1<<1
#define PKT_REROUTE  1<<2
#define PARAGON_POLL 1<<3
#define PKT_ERROR 1<<4
#define CORRUPT_PACKET  1<<5
#define PREMATURE_EOF   1<<6
#define CORRUPT_PKT_END 1<<7

#define COPY_BUFFER_SIZE 4096

#define MIN_PKT_BUF  4096
#define MAX_PKT_BUF  200000

int set_pc_netnode(void);


/// SkipPackedMsgHeader
char * SkipPackedMsgHeader(char *d, char *bufend)
{
   /*
   We need to check the length of the four null-termnated strings
   here and compare to maximum lengths for validity. If lengths
   are not valid, return something to act as a flag for this
   and dump the message(s)/save the packet as corrupt.
   */

   int i;

   //added 2/13/94
   int actual[4]={
      0,0,0,0}
   ;
   int ok[4]={
      19,35,35,71}
   ;
   //end added 2/13/94

   d=d+sizeof(struct PackedMsg)   -20;  /*the -20 is a hack*/

   for(i=0;i<4;i++)
   {
      while(*d++)
      {
         ;
         actual[i]++;    //this line added 2/13/94
      }

      if(d>=bufend) return(bufend);
   }

   //added 2/13/94  we have some lengths...
   for(i=0;i<4;i++)
   {
      if(actual[i]>ok[i])
      return 0;
   }
   // end added 2/13/94

   return(d);
}
//-

/// FetchArea
char * FetchArea(char *name)
{
   struct area *as;

   as=find_area_name(a,name);
   if(!as)  return(0);

   return(get_path(as));
}
//-

/// FetchPassthru
BOOL FetchPassthru(char *name)
{
   struct area *as;
   short x;

   as=find_area_name(a,name);
   if(!as) return(0);

   x=get_passthru(as);
   if(x) return(TRUE);
   else return(FALSE);
}
//-

/// FetchLink
BOOL FetchLink(char *name)
{
   struct area *as;
   short x;

   as=find_area_name(a,name);
   if(!as) return(0);

   x=get_link(as);
   if(x) return(TRUE);
   else return(FALSE);
}
//-

/// AreasClose
void AreasClose()
{
   delete_areas(a);
}
//-

/// PreScanForLength
PreScanForLength(char *c)
{
   int i;

   for(i=0;;i++)
   {
      if(*c==NULL) break;
      c++;
   }
   return(i);
}
//-

/// GetEchoArea
GetEchoArea(char *search, char *echo_area)
{
   int i;
   int j;
   char *oldsearch;

   oldsearch=search;
   i=stcpma(search,"AREA:");
   j=stcpma(search,"AREA:");

   if(i!=5 && j!=6)
   return(0);  /* apparently not an echo area */   

   if(i==5)
   {
      search += 5;
   }
   if(j==6)
   {
      search += 6;
   }

   /* we're now sitting on top of the first character of the areaname */

   search=stpblk(search);  /* this may cause problems if there is no blank */
   
   search=stptok(search,echo_area,40," \r\n\t");

   /* now we're sitting on top of either a space, return or linefeed or tab or null */

   for(;;)  /* skip crap after the tagname */
   {
      if(*search=='\r' || *search=='\n') break;
      search++;
   }

   for(;;)
   {
      if(*search=='\r' || *search== '\n')
      {
         search++;
         continue;
      }
      break;
   }
   return(search-oldsearch);
}
//-

/// AddToEXP
AddToEXP(char *tagname,int num)
{
   int i;

   if(!Stricmp(tagname,"MAIL_DIR")) return(0);
   if(!Stricmp(tagname,"BAD_MSGS")) return(0);

   if(totREMEMBEREXP)
   {
      for(i=0;i<totREMEMBEREXP;i++)
      {
         if(!Stricmp(tagname,REMEMBERAREA[i]))
         {
            REMEMBEREXPTALLY[i]++;
            return(0);
         }
      }
   }
   if(totREMEMBEREXP<MAXEXPAREAS)
   {
      strcpy(REMEMBERAREA[totREMEMBEREXP],tagname);
      REMEMBERAREALOW[totREMEMBEREXP]=num;
      REMEMBEREXPTALLY[totREMEMBEREXP]=1;
      totREMEMBEREXP++;
   }
   return(0);
}
//-

/// WriteEXP
WriteEXP()
{
   BPTR fp;
   int i;

   fp = Open("FIDO:DLGMail.EXP",MODE_NEWFILE);

   if(fp)
   {
      for(i=0;i < totREMEMBEREXP;i++)
      {
         AFPrintf(NULL,fp,"%s\n",REMEMBERAREA[i]);
      }

      Close(fp);

      if(_VERBOSITY) Log(". File Fido:DLGMail.EXP written");
   }
   else
   {
      Log("! Error: Couldn't write Fido:DLGMail.EXP");
   }

   return(0);
}
//-

/// NotateTosses
NotateTosses()
{
   int i;
   char clockstring[25];
   char filename[100];
   char lastreset[100];
   char *storagepath;
   BPTR fp;
   char *s;
   char buf[100];
   int previous;

   if(totREMEMBEREXP==0) return(0);

   /* leave the following in */
   AFPrintf(NULL,sout,"                                                      \n");

   AFPrintf(NULL,sout,"Logging Imported Messages for %d Areas\n",totREMEMBEREXP);
   if(_VERBOSITY) Log(". Notating Tosses");

   DTG(clockstring,TRUE);

   for(i=0;i<totREMEMBEREXP;i++)
   {
      storagepath=FetchArea(REMEMBERAREA[i]);
      
      if(_ACTIVITYLOG) LogImported(REMEMBEREXPTALLY[i],0,0,storagepath,REMEMBERAREA[i]);

      previous=0;
      strcpy(lastreset,clockstring);
      ASPrintf(NULL,filename,"%sIMPORT.DAT",storagepath);

      fp = Open(filename,MODE_OLDFILE);

      if(fp)
      {
         s = FGets(fp,buf,98);

         if(s != NULL)
            previous=atoi(buf);

         s = FGets(fp,buf,98);
         s = FGets(fp,buf,98);
         strcpy(lastreset,buf);
         Close(fp);
      }

      fp = Open(filename,MODE_NEWFILE);

      if(fp)
      {
         previous+=REMEMBEREXPTALLY[i];
         AFPrintf(NULL,fp,"%d\n%s\n%s\n",previous,clockstring,lastreset);
         Close(fp);
      }
   }

   if(_VERBOSITY) Log(". Done Notating Tosses");

   return(0);
}
//-

int pc_net;
int pc_node;

/// set_pc_netnode
set_pc_netnode()
{
   int pc_zone;
   char b[100];

   if(pc_net && pc_node)
   return 1;

   strncpy(b,_PCADDRESS,99);
   b[99]=0;

   sscanf(b,"%d:%d/%d",&pc_zone,&pc_net,&pc_node);
   ASPrintf(NULL,logstring,". Planet Connect net:%d node:%d",pc_net,pc_node);
   Log(logstring);
}
//-

/// tzmain

/********************
*                    *
*  NEW TZMAIN CODE   *
*                    *
 ********************/

int tzmain(char *pktname, int pktnum, int pktof)
{
   char *r;
   FILE *fp;

   ULONG msgtype;
   int i;
   int error=0;

   unsigned long length;
   unsigned long bufferlength;
   unsigned long filepos;

   long packet_length;
   
   char pktpath[255];
   char string[255];
   char fnstring[100];
   char str[255];

   BPTR infh;
   BPTR outfh;

   unsigned char *copybuffer;
   unsigned char *c;
   unsigned char *d;
   unsigned char *buffer;
   unsigned char *bufferend;  /* byte after last valid byte of buffer, always 0 */

   if(_PCFRIENDLY)
   set_pc_netnode();

   ASPrintf(NULL,pktpath,"INBOUND:%s",pktname);

   AFPrintf(NULL,sout,"\nTossing [[33m%s[0m] (Packet %d of %d)\n\n",pktname,pktnum,pktof);

   fp=fopen(pktpath,"r");

   if(!fp)
   {
      AFPrintf(NULL,sout,"ERROR: Couldn't open %s\n",pktpath);
      return FILE_ERROR;
   }
   
   fseek(fp,0,2);
   packet_length=ftell(fp);
   if(packet_length==0) packet_length=1;


   if(_VERBOSITY>5)
   {
      ASPrintf(NULL,logstring,"+ SPECIAL DEBUGGING: packet length is %d",packet_length);
      Log(logstring);
   }

   /************* packet termination hack **************/
   {
      BOOL hackflag=FALSE;
      int hack_a;
      int nullcount=0;
      char *hack_s;
      char *hack_p;
      int endsize=0;

      endsize=min(140,packet_length);

      hack_s=(void *)calloc(endsize+10,1);

      if(hack_s)
      {
         fseek(fp,-endsize,2);
         hack_a=fread(hack_s,1,endsize,fp);
         hack_p=hack_s;

         hack_p+=endsize;

         for(;hack_p>hack_s;hack_p--)
         {
            switch(*hack_p)
            {
               case 0:
               nullcount++;
               if(nullcount==3) hackflag=TRUE;
               break;

               case 2:

               if(_VERBOSITY>5)
                  Log("+ MEBBS-type packet");

               case '\r':
               case '\n':
               case '(':
               case ')':
               case '/':
               case ' ':
                  hackflag=TRUE;
               break;

               default:
                  nullcount=0;
            }

            if(hackflag) break;
         }

         free(hack_s);

         if(nullcount != 3)
         {
            ASPrintf(NULL,logstring,"! ERROR: Corrupt end of packet");
            Log(logstring);
            AFPrintf(NULL,sout,"%s\n",logstring);
            fclose(fp);

            if(_SAVEDAMAGED)
               SaveCorruptFile(pktpath);
            else
               DeleteFile(pktpath);

            return CORRUPT_PKT_END;
         }
      }
   }
   /********** end packet termination hack **********/

   if(_VERBOSITY>5)
      Log("+ Past packet termination code");

   rewind(fp);

   strcpy(string,""); /*use for returning rerouted packet name*/
   error=get_packet_header(fp,string,fnstring);

   if(error)
   {
      fclose(fp);

      if(error==PARAGON_POLL)
      {
         if(_VERBOSITY) Log("! Warning: short packet detected");
         DeleteFile(pktpath);
      }

      if(error==PKT_REROUTE)
      {
         AFPrintf(NULL,sout,"WARNING: Packet was intended for %s\n",fnstring);

         if(_VERBOSITY)
         {
            ASPrintf(NULL,logstring,"! WARNING: Packet not for me, it's for %s",fnstring);
            Log(logstring);
         }

         if(_PKTROUTE)
         {
            AFPrintf(NULL,sout,"Rerouting packet\n");
            ASPrintf(NULL,logstring,". Rerouting packet");
            Log(logstring);

            SetComment(pktpath,fnstring);
            ASPrintf(NULL,str,"OUTBOUND:%s",string);
            AFPrintf(NULL,sout,"rerouting %s to %s\n",pktpath,str);

            copybuffer=(char *)AllocMem(COPY_BUFFER_SIZE,MEMF_PUBLIC);

            if(copybuffer)
            {
               infh=Open(pktpath,MODE_OLDFILE);

               if(infh)
               {
                  outfh=Open(str,MODE_NEWFILE);

                  if(outfh)
                  {
                     for(;;)
                     {
                        i=Read(infh,copybuffer,COPY_BUFFER_SIZE);
                        if(i) Write(outfh,copybuffer,i);
                        if(i < COPY_BUFFER_SIZE) break;
                     }

                     Close(outfh);
                     SetComment(str,fnstring);
                     _RETURNCODE |=ACT_DLGBUN;
                  }

                  Close(infh);
                  if(outfh) DeleteFile(pktpath);
               }
               
               FreeMem(copybuffer,COPY_BUFFER_SIZE);
            }
            else
            {
               AFPrintf(NULL,sout,"Can't copy so we'll rename to process later\n");
               Log("* Error in copy of packet, renaming to process later");
               ASPrintf(NULL,str,"INBOUND:%s",string);
               SmartRename(pktpath,str);
            }
         }
         else
         {
            Log("* Not set to reroute packet, deleting");
            DeleteFile(pktpath);
         }
      }

      return PKT_ERROR;
   }
   else
   {
      if(_VERBOSITY>5)
         Log("+ No get_packet_header() error");
   }

   buffer=0;

   bufferlength=_PKTBUFFERLENGTH ? _PKTBUFFERLENGTH : 10240;

   if(bufferlength<MIN_PKT_BUF)  bufferlength=MIN_PKT_BUF;

   if(bufferlength>MAX_PKT_BUF)  bufferlength=MAX_PKT_BUF;

   if(_VERBOSITY>5)
      Log("+ Determined buffer length");


/// First loop, buffer is empty
   for(;;)  /* On this loop, The buffer is empty. */
   {
///   If buffer is not yet allocated, do so.
      if(!buffer)       /* if we haven't allocated the buffer yet, do so.    */
      {
         /* (May also occur if buffer needs to be reallocated */
         /* with a bigger size.)                              */
         buffer=malloc(bufferlength+1);

         if(!buffer)
         {
            fclose(fp);
            AFPrintf(NULL,sout,"ERROR: Out of memory\n");
            Log("! ERROR: Out of memory");

            // new shit as of 2/13/94
            if(bufferlength>128000)
            {
               //clearly, something is very wrong and we shouldn't try to continue
               //to try to process this message or packet...

               //the packet is closed, so maybe we rename it?

               strcpy(string,pktpath);
               r=strchr(string,'.');

               if(r)
               {
                  *r=0;
                  strcat(string,"2BIG");
                  SmartRename(pktpath,string);
                  ASPrintf(NULL,logstring,"! Renaming %s to %s as something in this packet requires a buffer beyond 128K",pktpath,string);
                  Log(logstring);
               }
            }
// end new shit 2/13/94
                  return OUT_OF_MEMORY;
            }
         }
//-
     
      length=bufferlength;
      filepos=ftell(fp);
      memset(buffer,69,bufferlength);
      error=!fread(buffer,bufferlength,1,fp);

      if(error)
      {
         length=ftell(fp)-filepos;

         if(length==0)
         {
            if(buffer) free(buffer);

            fclose(fp);

            AFPrintf(NULL,sout,"WARNING: Premature end of file\n");
            Log("! WARNING: Premature EOF, saving packet");

            if(_SAVEDAMAGED)
               SaveCorruptFile(pktpath);
            else
               DeleteFile(pktpath);

            return PREMATURE_EOF;
         }
      }
      
      bufferend=buffer+length;
      *bufferend=0;

      
   for(c=buffer;;) /* look for messages in filled buffer. */
   {


   /*
    *
    * This piece of code *appears* to have a problem if the null byte
    * terminating the message falls EXACTLY on the last byte of the
    * real buffer. This doesn't happen very often, of course, but it
               * can and we need to deal with it...
               *
               * if the null byte falls on the last byte of the buffer, or
               * last byte -1 of the buffer, then the buffer needs to be
               * reloaded
               *
               *
               */

      msgtype=256*c[1]+c[0];

///   Detected corrupt packet -- save
      if(msgtype != 0 && msgtype != 2)
      {
         fclose(fp);
         AFPrintf(NULL,sout,"WARNING: Corrupt packet, saving\n");
         ASPrintf(NULL,logstring,"! WARNING: Corrupt packet, saving     <%c><%c>  ([%d] [%d])\n",c[0],c[1],c[0],c[1]);
         Log(logstring);
         SaveCorruptFile(pktpath);
         free(buffer);
         return(CORRUPT_PACKET);
      }
//-

      if(msgtype==0)
      {
         fclose(fp);
         free(buffer);
         AFPrintf(NULL,sout,"<0> [100%] [33mEnd of packet[0m\n");
         DeleteFile(pktpath);
         return(NO_ERROR);
      }

      d=SkipPackedMsgHeader(c,bufferend);


///   Corrupt packet header
      if(d==0)
      {
         fclose(fp);
         free(buffer);
         AFPrintf(NULL,sout,"WARNING: Corrupt packet, message header invalid, saving\n");
         ASPrintf(NULL,logstring,"! WARNING: Corrupt packet, message header invalid, saving  [%d] [%d]\n",c[0],c[1]);
         Log(logstring);
         SaveCorruptFile(pktpath);
         return(CORRUPT_PACKET);
      }
//-

      if(d < bufferend)
      {
         while(*d++) /* this finds location of first zero after c. */
                  ;
         *d--;
      }

      if(d>=bufferend)
      {
         if(_VERBOSITY>2)
            Log(". Hit end of buffer, figuring out what to do");
                  
         if(c==buffer) /* single message too big for buffer. */
         {
            if(_VERBOSITY>1) Log(". Message too big for buffer, reallocating");
            fseek(fp,filepos,0); /* go back to start of message.       */
            free(buffer);        /* deallocate buffer.                 */
            buffer=0;            /* tag so buffer will be reallocated. */
            bufferlength <<= 1;  /* multiply bufferlength by two.      */
            break;               /* try again with bigger buffer.      */
         }

                        /* Last message not entirely in buffer. */

         fseek(fp,filepos+(c-buffer),0); /* Go back to start. */
         break;                     /* try again from start of buffer. */
      }
      else

         /* figure out where we are relative to the file */

         /* filepos=where we are relative to buffer
               c is relative to buffer, that is c-buffer = bytes
               + filepos divided by packet_length should give
               us a %age */

      toss_message(c, ((c-buffer+filepos)*100)/packet_length);
      c=d+1;

   /*
               *
               * This is where we need to deal with that problem... if c> bufferend
               *
               * the two tests below will detect the condition we need to test for,
               * and will be true when we need to reload the buffer - Ross, all
               * you need to do is to come up with the code to reload the buffer
               * and we'll be in good shape again :-)
    *
    */


         if(c+1>=bufferend)
         {
            fseek(fp,filepos+(c-buffer),0); /* Go back to start. */
            break;
         }
      }// the c=buffer loop

      }
//-

   Log("! ****** MAJOR BIG-TIME OOPS - REPORT THIS! ******");
}
//-

/// get_packet_header
get_packet_header(FILE *fp, char *newname, char *filenotestring)
{
   char hexnet[10];
   char hexnode[10];
   char buffer[100];
   int a;

   a=fread(buffer,1,58,fp);   /* ack! this is inefficient! */

   if(a!=58) return(PARAGON_POLL);

   if(IsPKTToMe((struct Packet_Header *)buffer,filenotestring,hexnet,hexnode))
   {
      CreatePKTName(newname);    
      return(PKT_REROUTE);
   }
   else
      return(NULL);
}
//-

/// IsPKTToMe
IsPKTToMe(struct Packet_Header *ph, char *whoitwasto,char *hexnet, char*hexnode)
{
   int i;
   int tnet;
   int tnode;

   short Onet, Onode, Dnet, Dnode;

   if(_PKTROUTE>1) return(0); /* ignore address of packets */

   Onet=FixNumbers(ph->OrigNet);
   Onode=FixNumbers(ph->OrigNode);
   Dnet=FixNumbers(ph->DestNet);
   Dnode=FixNumbers(ph->DestNode);

   /* ignore zone and point */
   if(MyDEBUG)
   {
      AFPrintf(NULL,sout,"Packet: ");
      AFPrintf(NULL,sout,"OrigNet=%5d  ",Onet);
      AFPrintf(NULL,sout,"OrigNode=%5d  ",Onode);
      AFPrintf(NULL,sout,"DestNet=%5d  ",Dnet);
      AFPrintf(NULL,sout,"DestNode=%5d\n\n",Dnode);
   }

   for(i=0;i<_totADDRESS;i++)
   {
      tnet=AddressToNet(_ADDRESS[i]);
      tnode=AddressToNode(_ADDRESS[i]);

      if(Dnet==tnet & Dnode==tnode)
      {
         if(MyDEBUG) AFPrintf(NULL,sout,"Packet is OK and will be tossed\n");
         return(0);
      }
   }

   ASPrintf(NULL,whoitwasto,"%d:%d/%d.0",AddressToZone(_ADDRESS[0]),Dnet,Dnode);
   sprintf(hexnet,"%04.4X",Dnet);
   sprintf(hexnode,"%04.4X",Dnode);

   return(1);
}
//-

/// SaveCorruptFile
SaveCorruptFile(char *oldname)
{
   char string[255];

   strcpy(string,oldname);

   string[strlen(string)-3]=NULL;
   strcat(string,"DMG");
   DeleteFile(string);
   SmartRename(oldname,string);
   return(0);
}
//-

/// AFTag
AFTag(int num)
{
   BPTR fp;

   fp = Open("t:AFX_LIST",MODE_READWRITE);

   if(fp)
   {
      Seek(fp,0,OFFSET_END);
      AFPrintf(NULL,fp,"%d\n",num);
      Close(fp);
   }

   return(1);
}
//-

/// StowIt
StowIt(char *where, char *what, int length, BOOL passthru, char *whybad)
{
   int oldlo;
   int oldhi;
   int newlo;
   int newhi;
   int target;
   int i;
   int k;
   int l;
   int areanum;

   char ptrfil[25];
   char DeleteMe[100];
   char StoreMe[100];
   char PointerMe[100];
   char SubDir[20];
   char tpr[100];

   FILE *pointerfile;

   BPTR msgfile;


   for(k=0;where[k] != ':';k++)
      ;

   k++;

   for(i=0;where[i+k] != NULL;i++)
   {
      SubDir[i]=where[i+k];
   }

   SubDir[i]=NULL;

   areanum=atoi(SubDir);

   /* check to see if directory is present */

   strcpy(tpr,where);
   tpr[strlen(where)-1]=NULL; /* get rid of slash */


   /*
    * Create a passthru directory if it doesn't exist already,
    * but we won't create a directory if its supposed to be
    * a local area...
    * 
    */

   msgfile=Lock(tpr,ACCESS_READ);

   if(!msgfile)
   {
      if(passthru)
      {
         msgfile=CreateDir(tpr);
      }
   }

   if(msgfile)
   {
      UnLock(msgfile);

      if(!passthru) MyBorrowArea(areanum);

      ASPrintf(NULL,PointerMe,"%sPOINTERS.MSG",where);

      pointerfile=fopen(PointerMe,"r+");

      if(!pointerfile)
      {
         if(MyDEBUG) AFPrintf(NULL,sout,"Can't open %sPOINTERS.MSG for read/write\nBuilding new pointers...\n",where);

         ASPrintf(NULL,logstring,". Can't open old %sPOINTERS.MSG - creating new one",where);
         Log(logstring);

         pointerfile=fopen(PointerMe,"w");

         if(!pointerfile)
         {
            Log("! ERROR: Can't open NEW POINTERS.MSG - returning");
            AFPrintf(NULL,sout,"Can't create %sPOINTERS.MSG for read/write\n",where);
            if(!passthru) UnBorrowArea(areanum);
            return(0);
         }

         if(!Strnicmp(where,"USER:",5))
            fprintf(pointerfile,"1\n0\n");
         else
            fprintf(pointerfile,"2\n2\n");
         
         fclose(pointerfile);
         Delay(50);

         pointerfile=fopen(PointerMe,"r+");

         if(!pointerfile)
         {
            Log("! ERROR: Can't open newly created POINTERS.MSG - returning");
            AFPrintf(NULL,sout,"ERROR: Can't open newly created %sPOINTERS.MSG for read/write\n",where);
            if(!passthru) UnBorrowArea(areanum);
            return(0);
         }
      }
      fgets(ptrfil,10,pointerfile);
      oldlo=atoi(ptrfil);
      fgets(ptrfil,10,pointerfile);
      oldhi=atoi(ptrfil);

      l=oldhi-oldlo+1;  /* the number of msgs currently in area */

      k=HowMany(areanum); // the capacity of this area

      newlo=oldlo;
      newhi=oldhi;

      if((l+1)>k)
      {
         newlo=oldlo+(l-k)+1;

         for(i=oldlo;i<(newlo);i++)
         {
            ASPrintf(NULL,DeleteMe,"%s%d.MSG",where,i);
            DeleteMsg(DeleteMe);
            if(MyDEBUG) AFPrintf(NULL,sout,"%s Deleted...\n",DeleteMe);
         }
      }

      target=oldhi+1;

      ASPrintf(NULL,StoreMe,"%s%d.MSG",where,target);
      msgfile=Open(StoreMe,MODE_NEWFILE);

      if(msgfile)
      {
         newhi++;
         i=Write(msgfile,what,length);

         if(*whybad)
         {
            Write(msgfile,whybad,strlen(whybad));
         }

         Close(msgfile);
      }

      rewind(pointerfile);
      fprintf(pointerfile,"%d\n%d\n",newlo,newhi);
      fclose(pointerfile);

      if(!passthru) UnBorrowArea(areanum);

      return(target);/* returning the message number it was stored to */
   }

   AFPrintf(NULL,sout,"ERROR! Missing %s subdirectory\n",where);
   return(-1); /* -1 is flag for missing subdirectory */
}
//-

/// HowMany
/*following should be OK */
long HowMany(long areanum)
{
   long i;

   if(MyDEBUG>1) AFPrintf(NULL,sout,"\n");

   for(i=0;i<TotalAreas;i++)
   {
      strcpy(localareaname,AllAreas[i].Name);

      if(MyDEBUG>1) AFPrintf(NULL,sout,"[Aarea %d, name %s, capacity %d\n",
                                        AllAreas[i].Number,AllAreas[i].Name,
                                        AllAreas[i].Capacity);

      if(AllAreas[i].Number != areanum) continue;

      return(AllAreas[i].Capacity);
   }

   return(1000);
}
//-

/// DeleteMsg
/* following is OK */
DeleteMsg(char *deleteme)
{
   /* deleteme will contain full path and msg number...
      
      if device != MSG: then just delete it
      otherwise break it down into components for later,
      open the damned thing, see who it's to, check the
               received bit. if the received bit is set, just delete
               it. if not, see if the user is on this system and if so,
               check his waitingmail.dat file and remove entry as necessary */

   BPTR fh;

   struct Msg_Header *dmh;

   char Dev[31];
   char Dirnumber[51];
   char Msgnumber[31];
   char MsgExt[31];
   char pathcrap[150];

   char *me;


   dmh=NULL;
   dmh=(struct Msg_Header *)calloc(sizeof(struct Msg_Header),1);

   strsfn(deleteme,Dev,Dirnumber,Msgnumber,MsgExt);

   if(Stricmp(Dev,"MSG:") || dmh==NULL)
   {
      DeleteFile(deleteme);
      free(dmh);
      return(0);
   }

   fh=Open(deleteme,MODE_OLDFILE);

   if(fh)
   {
      Read(fh,dmh,sizeof(struct Msg_Header));
      Close(fh);
   }

   if(fh==NULL || (dmh->Attribute&4))
   {
      DeleteFile(deleteme);
      free(dmh);
      return(0);
   }

   /* build fucking path crap */

   ASPrintf(NULL,pathcrap,"USER:%s/WaitingMail.dat",dmh->To);

   me=pathcrap;

   while(*me!=NULL)
   {
      if(*me==' ') *me='_';
      me++;
   }

   DeleteWM(pathcrap,atol(Dirnumber),atoi(Msgnumber));

   DeleteFile(deleteme);
   free(dmh);
   return(0);
}
//-

/// toss_message
/*******************************************************************************
*                    ***********************************************************
*  NEW TOSSMSG CODE  ***********************************************************
*                    ***********************************************************
 ******************************************************************************/

toss_message(unsigned char *mp,int positionage)
{
   struct Fido_Msg_Header *FMH;
   
   int IT_IS_TO_US=0;

   int ECHOMAIL;
   int mem_allocated;
   int sizetostore;
   int mnum;
   int j;
   int return_code;
   int pctg;
   int usernum;
   int ii;

   BOOL VSN;   /* vector sysop netmail */
   BOOL OURUSER=FALSE;
   BOOL bad_flag;
   BOOL THIS_IS_NETMAIL;

   BOOL BACKGROUNDEXPORT=FALSE;

   unsigned char *c;
   char *top_of_body;
   char *msg_buffer;
   char *storagepath;

   UBYTE *MsgBuffer; 

   char TTo[100];
   char Date[100];
   char To[100];
   char From[100];
   char Subject[100];
   char EchoArea[100];
   char addstring[100];
   char crapstring[100];
   char usp[100];

   char badtag[150];
   char badreason[150];

   ULONG bodysize;
   ULONG msgtype;
   ULONG onet;
   ULONG onode;
   ULONG dnet;
   ULONG dnode;
   ULONG attrib;
   ULONG attribmask;
   ULONG cost;

   BOOL PASSTHRUFLAG=FALSE;

   c=mp;

   attribmask=PRIVATE+FILEATTACHED+INTRANSIT+FILEREQUEST+RRREQUEST+ISRR+AUDREQ+FILEUPREQ;

   msgtype=256*c[1]+c[0];

   if(msgtype==2)
   {
      c+=2;

      AFPrintf(NULL,sout,"<%d> ",msgtype);

      onode=256*c[1]+c[0]; c+=2;
      dnode=256*c[1]+c[0]; c+=2;
      onet=256*c[1]+c[0];  c+=2;
      dnet=256*c[1]+c[0];  c+=2;
      attrib=256*c[1]+c[0];   c+=2;
      cost=256*c[1]+c[0];  c+=2;

      /* point of argument on how to handle friggin date field
               please note that a previous function assumes it's a null string */

      j=stccpy(Date,c,80); c += j;
      j=stccpy(To,c,80);   c += j;
      j=stccpy(From,c,80); c += j;
      j=stccpy(Subject,c,80); c += j;

      /* we're now at the top of the body of the message */

      top_of_body=c;

      /* remember where we are :-) */

      THIS_IS_NETMAIL=FALSE;

      ECHOMAIL=GetEchoArea(c,EchoArea);

      if(ECHOMAIL==NULL)
      {
         strcpy(EchoArea,"MAIL_DIR");
         THIS_IS_NETMAIL=TRUE;
         GOTNETMAIL=TRUE;
         storagepath=_NETMAILDIRPATH;
      }
      else
      {
         BACKGROUNDEXPORT=TRUE;

         c+=ECHOMAIL;
         GOTECHOMAIL=TRUE;
         storagepath=FetchArea(EchoArea);
      }

      PASSTHRUFLAG=FetchPassthru(EchoArea);

      strcpy(badtag,"");
      strcpy(badreason,"");

/*** SECURITY HACK ***/

      if(GOTECHOMAIL && _SECUREIMP) /* MAKE THIS CONFIGURABLE */
      {
         if(SecurityCheck(EchoArea,onet,onode)==NULL)
         {
            char xxx[100];

            ASPrintf(NULL,xxx,"SECURITY FAILURE, Node %d/%d not configured",onet,onode);
            Reasoning(EchoArea,badreason,xxx);
            storagepath=NULL;
            ASPrintf(NULL,logstring,"! ERROR: Origination [%d/%d], echo [%s] failed security test",onet,onode,EchoArea);
            Log(logstring);
            BACKGROUNDEXPORT=FALSE;
         }
      }

/*********************/

      if(storagepath==NULL)   /*no such tagname in areas.bbs*/
      {
         BACKGROUNDEXPORT=FALSE;

         if(_PCFRIENDLY==0)
         {
            storagepath=_BADMSGSDIRPATH;
            ECHOMAIL=0;
            c=top_of_body; /* <--- show the bad tagname */
         }
      }

      if(storagepath)
      {
         /* prescan to determine needed buffer for the message and
               allocate accordingly */

         bodysize=PreScanForLength(c);

         /* allocate enough space for the body plus the header (190) plus a little extra */

         mem_allocated=bodysize+1024;
         msg_buffer=(char *)AllocMem(mem_allocated,MEMF_PUBLIC | MEMF_CLEAR);

         if(!msg_buffer)
         {
            AFPrintf(NULL,sout,"ERROR: Problem allocating %d bytes for msg - losing\n",mem_allocated);
            return_code=-25;
            ASPrintf(NULL,logstring,"! ERROR: Couldn't allocate %d bytes for message, msg lost",mem_allocated);
            Log(logstring);
            return(-1);
         }

         MsgBuffer=(void *)msg_buffer;

         /* copy the header into our newly allocated space */

         FMH=(void *)msg_buffer;
         strcpy(FMH->From,From);
         FMH->From[35]=NULL;

         strcpy(FMH->To,To);
         FMH->To[35]=NULL;

         strcpy(FMH->Title,Subject);
         FMH->Title[71]=NULL;

         strcpy(FMH->Date,Date);
         FMH->Date[19]=NULL;

         FMH->TimesRead=0;
         FMH->DestNode=dnode;
         FMH->OrigNode=onode;
         FMH->Cost=0;
         FMH->OrigNet=onet;
         FMH->DestNet=dnet;
         FMH->ReplyTo=0;
         FMH->Attribute=(attrib & attribmask);/* get rid of crashmail bit */
         FMH->NextReply=0;

         if(THIS_IS_NETMAIL)
            FMH->TimesRead=2;  /* TPT's "flag" for netmail */

         IT_IS_TO_US=OneOfOurs(FMH->DestNet,FMH->DestNode);

         OURUSER=SearchUsers(To);

         /*
          * This code here determines if a message addressed to SYSOP is
          * actually to us, then flags it for moving to the operator of
          * the system...
          *
          */


         VSN=FALSE;

         if(THIS_IS_NETMAIL)
         {
            if(!Stricmp(To,"SYSOP"))
            {
               if(IT_IS_TO_US)
               {
                  VSN=TRUE;
               }
            }
         }

         /* check for junk file attaches */

         /*
          * Check for "junk arcmail file attaches" and jump the hell out
          * of saving the message if it really is junk...
          *
          */


         if(VSN && (FMH->Attribute & FILEATTACHED))
         {
            if(IsItAnARCMailName(FMH->Title))
            {
               if(_VERBOSITY) Log("+ arcmail attach message detected");
               goto skiptohere;
            }
         }

         if(!OURUSER && !THIS_IS_NETMAIL) FMH->Attribute |= 4; /* set the received bit for mail not destined for a user on this system */

         /* copy the buffer */

         j=stccpy(&MsgBuffer[sizeof(struct Msg_Header)],c,bodysize+1);
         c += j;

         pctg=0;

         /* new hack to show why msg was tossed to bad */

         if(_CHECKDUPES && ECHOMAIL)
         {
            if(DupCheck(storagepath,&MsgBuffer[sizeof(struct Msg_Header)],bodysize,EchoArea,badreason,FMH->Date,FMH->To,FMH->From,FMH->Title))
            {
               /* code what to do with a bad msg here... */
               ECHOMAIL=0;
               strcat(EchoArea," ");
               strcat(EchoArea,prob);
               storagepath=_BADMSGSDIRPATH;
               strcpy(badtag,badreason);
               BACKGROUNDEXPORT=FALSE;
            }
         }

         /* store the message */

         if(_PCFRIENDLY)
         {
            // added march '95 - checks for one of our addresses as first one
               // in path line, dumps the message to NIL: if it is...

               char *pth;
               int opn,opnd;
               //            char abd[50];

               {
                  pth=strstr(msg_buffer+sizeof(struct Fido_Msg_Header),"PATH: ");

                  if(pth)
                  {
                     pth+=7;

                     if(sscanf(pth,"%d/%d ",&opn,&opnd)>1)
                     {
                        if(_MyNet==(ULONG)opn && _MyNode==(ULONG)opnd)
                        {
                           if(onet==pc_net && onode==pc_node)
                           {
                              Log("+ Message being dumped - it came from me");
                              BACKGROUNDEXPORT=FALSE;
                              goto skiptohere;
                           }
                        }
                     }
                  }
               }
            }

            sizetostore=sizeof(struct Msg_Header)+bodysize; /*instead of bodysize, used to use j */   

            if(BACKGROUNDEXPORT == TRUE)
            {
               long rcsize;
               int sss;

               sss=(int)sizetostore;

               rcsize=(long)handlemsg2("", EchoArea, (char *)MsgBuffer,
                                       &sss, get_area_from_tagname(a,EchoArea));

               if(rcsize)
                  sizetostore=rcsize;

            }

            if(!PASSTHRUFLAG)
               mnum=StowIt(storagepath,(void *)MsgBuffer,sizetostore,PASSTHRUFLAG,badreason);

            MSGSIMPORTED++;

            if(THIS_IS_NETMAIL && 
            (!Stricmp(FMH->To,"Areafix")     ||
            !Stricmp(FMH->To,"PDQAreafix")  ||
            !Stricmp(FMH->To,"DLGAreafix")  ||
            !Stricmp(FMH->To,"Raid")        ||
            !Stricmp(FMH->To,"DLGRaid")     ||
            !Stricmp(FMH->To,"PDQRaid"))
            &&
            _ENABLE_AREAFIX)
            {
               AFTag(mnum);
            }

            usernum=0;

            /*
          *
          * there is a leak in message security here - before copying to a
          * private directory, we must first check to see if the message
          * was intended for one of our addresses. oops!
          *
          */

            if(THIS_IS_NETMAIL && _NET2USERDIR && IT_IS_TO_US)
            {
               if(OURUSER || VSN)
               {
                  if(VSN) strcpy(TTo,_OPERATOR);
                  else    strcpy(TTo,To);

                  ASPrintf(NULL,usp,"USER:%s",TTo);
                  ii=0;

                  while(usp[ii]!=NULL)
                  {
                     if(usp[ii]==' ') usp[ii]='_';
                     ii++;
                  }

                  strcat(usp,"/");
                  usernum=StowIt(usp,(void *)MsgBuffer,sizetostore,FALSE,"");
                  LogEvent(TTo,From,"Private Directory Netmail",usernum,0,"");
               }
            }

         /*
          *
          * We need to look for file attaches to points and "move" the file
          * attach to a different directory here so they will never be
          * picked up by DLGTick...
          *
          * As an experiment, we'll move them to OUTBOUND: and modify DLGNet
          * to do the flowfile deal with a ^ so they'll automatically be
          * deleted. This will, of course, fail when the same file is sent
          * to multiple points...
          *
          */

            if(IT_IS_TO_US && (FMH->Attribute & FILEATTACHED))
            {
               int pointdest=0;
               char commentbuf[100];

               if(pointdest=ToAPoint(&MsgBuffer[sizeof(struct Msg_Header)],bodysize))
               {
                  /* file attach is to a point */

                  ASPrintf(NULL,commentbuf,"To ?:%d/%d.%d",FMH->DestNet,FMH->DestNode,pointdest);

                  MovePointFileAttaches(FMH->Title,commentbuf);
                  if(_VERBOSITY) Log("--> Moved point file attaches to OUTBOUND:");
               }
            }

            /* log the transaction */

            if(_VERBOSITY==0) AFPrintf(NULL,sout,"[A");
            bad_flag=FALSE;

            if(!Stricmp(storagepath,_BADMSGSDIRPATH)) bad_flag=TRUE;
            
            if(bad_flag) AFPrintf(NULL,sout,"[33m");

            ASPrintf(NULL,addstring,"%d/%d->%d/%d",onet,onode,dnet,dnode);

            AFPrintf(NULL,sout,"[%3.3d%%] [%16.16s]=>[33m%-17.17s [32m[%s[0m%d[32m][0m[K",positionage,addstring,EchoArea,storagepath,mnum);

            if(bad_flag) AFPrintf(NULL,sout,"[0m");

            if(_VERBOSITY>1)
            {
               ASPrintf(NULL,logstring,". [%2.2d %%] [%25.25s ]=> %-20s [%s%d]",positionage,addstring,EchoArea,storagepath,mnum);
               Log(logstring);
            }

            if(ECHOMAIL)
               if(mnum>0)
                  AddToEXP(EchoArea,mnum);

            if((PASSTHRUFLAG==FALSE) && OURUSER && _LOGUSERMESSAGE && (bad_flag==FALSE) && usernum==0)
            {
               strsfn(storagepath,NULL,crapstring,NULL,NULL);
               if(mnum>0) LogEvent(To,From,EchoArea,mnum,atoi(crapstring),Subject);
            }

            AFPrintf(NULL,sout,"\n");

skiptohere:

            FreeMem(msg_buffer,mem_allocated);
         }
         else 
         {
            AFPrintf(NULL,sout,"Unconfigured area [%s]... Message sent to nowhere\n",EchoArea);
            NULLMSGS++;
         }
         return(0);
      }
      else
      {
         AFPrintf(NULL,sout,"ERROR: other function handed us a bad msg!?!?\n");

         ASPrintf(NULL,logstring,"! BAD MSG TYPE: [%d] [%d] \n",c[0],c[1]);
         Log(logstring);
         return(-1);
      }
   }
   //-
   /// OneOfOurs
   int OneOfOurs(USHORT tnet, USHORT tnode)
   {
      int i;
      char NET[10],NODE[10];
      int net,node;

      for(i=0;i<_totADDRESS;i++)
      {
         strsfn(_ADDRESS[i],NULL,NET,NODE,NULL);
         net=atoi(NET);
         node=atoi(NODE);

         if(tnet==net && tnode==node) return 1;
      }
      return(0);
   }
   //-
   /// IsItAnARCMailName
   int IsItAnARCMailName(char *name)
   {
      char *s;
      char buf[10];
      int i;
      char *arcmail[]={
"SU","MO","TU","WE","TH","FR","SA"}
      ;


      if(strlen(name)!=12) return 0;

      s=name;
      s+=8; /* sitting on period in extension */

      if(*s != '.') return 0;

      s++;

      strncpy(buf,s,3);

      for(i=0;i<7;i++)
      {
         if(!Strnicmp(buf,arcmail[i],2)) return 1;
      }
      return 0;
   }
   //-
/// ToAPoint
int ToAPoint(char *msg,int bodysize)
{
   char *s;
   char *p;

   s=msg;

   while(1)
   {
      p=strchr(s,1); /* look for CTRL A */

      if(p==NULL) break;

      if(p+1<(msg+bodysize))
      s=p+1;
      // BORSA BUG FIX
      else
      break;
      // END BORSA BUG FIX

      if(*s)
      {
         if(!Strnicmp(s,"TOPT ",5))
         {
            s+=5;
            return atoi(s);
         }
      }
   }
   return 0;
}
//-
/// MyMainCopy
/* the following function was stolen from DLGtick... */

#define COPYSIZE 10000

MyMainCopy(char *src, char *destination, char *comment,BOOL del)
{
   BPTR s;
   BPTR d;
   char source[100];
   char *copybuf;
   int rc=0;
   int i,j;

   strcpy(source,src);

   copybuf=(void *)calloc(COPYSIZE,1);
   if(!copybuf)
   return rc;

   if(!Exists(source))
   {
      free(copybuf);
      return rc;
   }

   s=Open(source,MODE_OLDFILE);
   if(s)
   {
      d=Open(destination,MODE_NEWFILE);
      if(d)
      {
         while(1)
         {
            i=Read(s,copybuf,COPYSIZE);
            j=Write(d,copybuf,i);
            if(j!=i)
            {
               rc=-1; /* error in copy */
               break;
            }
            if(i<COPYSIZE)
            {
               rc=1;  /* copy went well */
               break;
            }
         }
         Close(d);
      }
      Close(s);
   }
   free(copybuf);

   if(rc==-1)
   {
      DeleteFile(destination);
      rc=0;
   }

   comment[79]=NULL;

   if(rc==1)
   {
      if(*comment) SetComment(destination,comment);
      if(del) DeleteFile(source);
   }
   return rc;
}
//-
/// MovePointFileAttaches
int MovePointFileAttaches(char *subject,char *comment)
{
   char src[100];
   char dest[100];
   char *s;
   char token[80];
   char file[32];
   char ext[32];
   char actual[80];

   s=subject;

   while(1)
   {
      s=stpblk(s);
      if(*s==NULL) break;
      
      s=stptok(s,token,sizeof(token)," \t");

      strsfn(token,NULL,NULL,file,ext);

      strcpy(actual,file);

      if(*ext)
      {
         strcat(actual,".");
         strcat(actual,ext);
      }

      ASPrintf(NULL,src,"INBOUND:%s",actual);
      ASPrintf(NULL,dest,"OUTBOUND:%s",actual);

      MyMainCopy(src,dest,comment,TRUE);

      ASPrintf(NULL,logstring,"--> Moved point file attach: %s",dest);
      Log(logstring);
   }
   return 1;
}
//-
/// SecurityCheck
SecurityCheck(char *EchoArea,ULONG onet,ULONG onode)
   {
      struct area *as;
      struct nodenum *ndn;
      as=find_area_name(a,EchoArea);
      if(!as) return 1;

      if(onet!=_POINTNET)
      {
         for(ndn=as->first_nodenum;;ndn=ndn->next_nodenum)
         {
            if(onet==(ULONG)ndn->net && onode==(ULONG)ndn->node)
            {
               return 1;
            }
            else
            {
               if(ndn->next_nodenum==NULL)
               {
                  return 0;
               }
            }
         }
      }

      /* new code to accomodate the pointnet kludges... */

      else
      {
         for(ndn=as->first_nodenum;;ndn=ndn->next_nodenum)
         {
            if(_MyNet==(ULONG)ndn->net && _MyNode==(ULONG)ndn->node && onode==(ULONG)ndn->point)
            {
               return 1;
            }
            else
            {
               if(ndn->next_nodenum==NULL)
               {
                  return 0;
               }
            }
         }

      }

      /* end of new code */
   }
//-
/// DeleteWM
void DeleteWM(char *file, long areanum,int messagenum)
{
   struct WaitingMail *wm;

   wm = calloc(1,sizeof(struct WaitingMail));

   ASPrintf(NULL,wm->msgid,"%04.4d:%05.5d",areanum,messagenum);

   DeleteStruct(file,(char *)wm,sizeof(struct WaitingMail),12);

   free(wm);

   return;
}
//-


