#include <exec/types.h>
#include <stdio.h>
#include <libraries/dos.h>
#include <time.h>
#include <proto/dos.h>
#include <string.h>
#include <dos.h>
#include <stdlib.h>
#include <proto/dos.h>
#include <utility/tagitem.h>

#include "/zflavor/flavorproto.h"
#include "/ross/protos.h"
#include "/ross/header.h"
#include "/zap_h/zap.h"
#include <dlg/globalconfig.h>

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

//#include <proto/utility.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include <dlg/resman.h>
#include <dlg/msg.h>

#include "/DLGExp/ExpProtos.h"

#include "bpkt.h"

struct FASTOPEN
{
   struct FASTOPEN *next;
   BPTR fh;
   int size;
   char file[50];
};



#define MyDEBUG   (GCFG->ZEXP_DB)

#define DLGMV2 1
#define FASTER 1
#define PKTSIZELIMIT 250000
#define PKTHEADLENGTH 500
#define MLSLENGTH 2500

extern struct areas *a;
extern struct FASTOPEN *F_O_;

extern struct Library *DLGBase;
extern BPTR sout;

char bpktlogstring[10000];
BPTR PKTfile;
char *PKTHEADSTRUCT;
struct Packet_Header pkthead;
struct PackedMsg pktmsg;
struct FASTOPEN *F_O_=NULL;

extern int OpenPKT(int zone, int net, int node, int point, int fromzone, int fromnet, int fromnode, int frompoint);
extern int AppendToPKT(UBYTE *what, int howmuch);

int OUTBCREATED;
int X_NTA;
int WEXPORTED;
int PKTSMADE;
int MSGSPROCED;

/// exportreport
void exportreport()
{
   char b[100];

   if(WEXPORTED)
   {
      Log("## Export report:");
      
      ASPrintf(NULL,b," # Messages processed: %d",MSGSPROCED);
      Log(b);
      ASPrintf(NULL,b," #    Packets created: %d",PKTSMADE);
      Log(b);
      ASPrintf(NULL,b," #     Outbound nodes: %d",OUTBCREATED);
      Log(b);
      
      if(_RETURNCODE != ACT_QUIT)
      {
         _RETURNCODE |= ACT_DLGBUN;
      }
   }
}
//-

/// FileToPKT
int FileToPKT(int partialonly)
{
   //   we add a 0 byte for each .RAWPKT found and
   //   change the name to something that oMMM
   //   now understands 

   struct FileInfoBlock *FIB;

   int i;
   int j;
   char packets[100][30];
   char *pkts[100];
   int type;
   char *filename;
   char comment[50];

   char string[100];
   char newfilename[100];
   char partialnewfilename[100];

   char *notused;
   char *loc;
   char buffer[100];
   int zone,k,l,point;

   BPTR LockFile;

   FIB=AllocDosObject(DOS_FIB,TAG_END);
   if(!FIB) return(-10);

   if(_VERBOSITY)
   {
      ASPrintf(NULL,bpktlogstring,"-> .RAWPKT -> .PKT");
      Log(bpktlogstring);
   }


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

   if(LockFile)
   {
      i=Examine(LockFile, (void *)FIB);

      if(i)
      {
         j=0;

         while(1)
         {
            type=FIB->fib_DirEntryType;
            filename=FIB->fib_FileName;
            Upper(filename);

            if(type<0 && (0!=stcpm(filename,"RAWPKT",&notused)) && (FIB->fib_Size>=partialonly))
            {
               if(MyDEBUG) AFPrintf(NULL,sout,"Raw packet found: %s\n",filename);
               strcpy(packets[j],filename);
               pkts[j]=packets[j];
               j++;
            }

            i=ExNext(LockFile,(void *)FIB);
            if(!i) break;
         }

         tqsort(pkts,j);

         for(i=0;i<j;i++)
         {
            if(MyDEBUG) AFPrintf(NULL,sout,"Packets in ascending order: %s\n",pkts[i]);
         }
      }

      UnLock(LockFile);

      if(j)
      {
         for(i=0;i<j;i++)
         {
            filename=pkts[i];

            loc=memreaduntilterm(filename,buffer,".P");
            zone=atoi(buffer);

            loc=memskipchars(loc,".");
            loc=memreaduntilterm(loc,buffer,".P");
            k=atoi(buffer);

            loc=memskipchars(loc,".");
            loc=memreaduntilterm(loc,buffer,".P");
            l=atoi(buffer);

            loc=memskipchars(loc,".");
            loc=memreaduntilterm(loc,buffer,".P");

            CreatePKTName(partialnewfilename);
            ASPrintf(NULL,newfilename,"OUTBOUND:%s",partialnewfilename);

            point=atoi(buffer);

            ASPrintf(NULL,comment,"%d:%d/%d.%d",zone,k,l,point);

            TallyMsgs(zone,k,l,point,0);

            ASPrintf(NULL,buffer,"OUTBOUND:%s",filename);

            if(!SmartRename(buffer,newfilename))
            {
               if(MyDEBUG) AFPrintf(NULL,sout,"%s-->%s\n",buffer,newfilename);

               if(_VERBOSITY > 1) AFPrintf(NULL,sout,"%s -> %s",buffer,newfilename);

               if(_VERBOSITY)
               {
                  ASPrintf(NULL,bpktlogstring," | %s -> %s",buffer,newfilename);
                  Log(bpktlogstring);
               }

               PKTfile=Open(newfilename,MODE_OLDFILE);

               if(PKTfile)
               {
                  if(MyDEBUG) AFPrintf(NULL,sout,"opened packet\n");
                  strcpy(string,"");      /* ahem, null byte between messages */
                  Seek(PKTfile,0,OFFSET_END);
                  Write(PKTfile,(void *)string,1);
                  Seek(PKTfile,0,OFFSET_END);
                  Write(PKTfile,(void *)string,1);
                  Close(PKTfile);

                  if(_VERBOSITY>3)
                  {
                     ASPrintf(NULL,bpktlogstring," | Appended NULL byte");
                     Log(bpktlogstring);
                  }

               }
               else
               {
                  Log("!! ERROR: Couldn't append NULL byte");
               }
            }
            else
            {
               ASPrintf(NULL,bpktlogstring,"!! ERROR: Couldn't rename %s -> %s",buffer,newfilename);
               Log(bpktlogstring);
            }
         }
      }
   }
   else
   {
      Log("!! Couldn't get a lock on outbound:");
   }

   if(_VERBOSITY)
   {
      ASPrintf(NULL,bpktlogstring,"<- Done .RAWPKT -> .PKT");
      Log(bpktlogstring);
   }

   FreeDosObject(DOS_FIB,FIB);
   return(0);
}
//-

struct Tally
{
   struct Tally *next;
   int zone;
   int net;
   int node;
   int point;
   int tally;
};

struct Tally *TALLY=NULL;

/// TAllyMsgs
int TallyMsgs(int z, int N, int n, int p, int how)
{
   struct Tally *tally;
   struct Tally *t;

   tally=TALLY;

   if(tally==NULL)
   {
      tally=(void *)calloc(sizeof(struct Tally),1);

      if(tally)
      {
         TALLY=tally;
         tally->zone=z;
         tally->net=N;
         tally->node=n;
         tally->point=p;
         if(how) tally->tally++;
         return(1);
      }
   }

   for(;;tally=tally->next)
   {
      if(tally->zone==z && tally->net==N && tally->node==n && tally->point==p)
      {
         if(how)
            tally->tally++;
         else
            tally->tally=0;
         return(1);
      }
      if(tally->next==NULL)
         break;
   }

   t=(void *)calloc(sizeof(struct Tally),1);

   if(t)
   {
      tally->next=t;
      tally=t;

      tally->zone=z;
      tally->net=N;
      tally->node=n;
      tally->point=p;
      if(how) tally->tally++;
      return(1);
   }
   return(0);
}
//-
/// TallyThreshold
int TallyThreshold(int size)
{
   struct Tally *t;

   size=size/750;

   for(t=TALLY;;t=t->next)
   {
      if(t->tally>size) return(1);
      if(t->next==NULL) return(0);
   }
}
//-
/// ClearPKTStruct
int ClearPKTStruct(char *s,int size)
{
   int i;

   for(i=0;i<size;i++)
      s[i]=NULL;

   return(0);
}
//-
/// AppendToPKTStruct
int AppendToPKTStruct(char *buffer,int offset,char *string,int length)
{
   char *s,*d;
   int i;

   d=buffer + offset;
   s=string;

   for(i=0;i<length;i++)
   {
      *d++=*s++;
   }

   return(offset+length);
}
//-
/// GetPKTPw
int GetPKTPw(char *address, char *password, char *use)
{
   BPTR fp;
   char buf[100];
   char *s;
   char token[50];
   int rc=0;
   
   *password=0;
   *use=0;

   fp=Open("FIDO:DLGMail.PPW",MODE_OLDFILE);

   if(fp)
   {
      while(FGets(fp,buf,sizeof(buf)))
      {
         s=strchr(buf,'\n');
         if(s) *s=0;

         s=buf;
         s=stpblk(s);
         if(*s==';') continue;
         if(!*s) continue;

         s=stptok(s,token,sizeof(token)," \t");
         s=stpblk(s);
         if(!*s) continue;

         if(!Stricmp(address,token))
         {
            s=stptok(s,token,sizeof(token)," \t");
            s=stpblk(s);
            if(!*s) break;

            strncpy(password,token,8);
            password[8]=0;

            strncpy(use,s,8);
            use[8]=0;
            rc=1;
         }
      }
      Close(fp);
      return(rc);
   }
   return(-1); // no password file
}
//-
/// SearchFO
BPTR SearchFO(char *name)
{
   // search for name in our linked list, if found return FH, otherwise
   // return 0;

   struct FASTOPEN *this;

   for(this=F_O_;this != 0;this=this->next)
   {
      if(!Stricmp(this->file,name))
      {
         return(this->fh);
      }
   }

   return(0);
}
//-
/// FastOpen
BPTR FastOpen(char *name, long how)
{
   BPTR fh;
   struct FASTOPEN *new;

   fh=SearchFO(name);

   if(how == MODE_OLDFILE)
   {
      if(fh)
         return(fh);

      // its supposed to be an oldfile, but it isn't in our list,
      // so have DOS open it and add it to our list

      fh=Open(name,how);

      if(fh)
      {
         new=(void *)calloc(sizeof(struct FASTOPEN),1);

         if(new)
         {
            strcpy(new->file,name);
            new->fh=fh;
            new->next=F_O_;
            F_O_=new;
            return fh;
         }
         else
         {
            // no mem for fastopen struct //
            Close(fh);
         }

      }
      return(0);
   }

   if(how == MODE_NEWFILE)
   {
      if(fh)
      {
         // by our definition, this can't happen so figure
         // out how to deal with it here...

         AFPrintf(NULL,sout,"MAJOR BOOBOO - DLGExp wanted MODE_NEWFILE, we had MODE_OLDFILE\n");

         FastCloseAll();

         Log("!! Wanted newfile, got oldfile... Closed all packets and am exiting");

         exit(10);

      }

      fh=Open(name,how);

      if(fh)
      {
         new=(void *)calloc(sizeof(struct FASTOPEN),1);

         if(new)
         {
            strcpy(new->file,name);
            new->fh=fh;
            new->next=F_O_;
            F_O_=new;
            return fh;
         }
         else
         {
            // no mem for fastopen struct //
            Close(fh);
            return(0);
         }
      }
   }

   return(0);
}
//-
/// FastClose
int FastClose(BPTR fh)
{
   struct FASTOPEN *last=0,*this;

   for(this=F_O_;this!=0;this=this->next)
   {
      if(this->fh == fh)
      {
         Close(fh);

         if(last==0)
         {
            F_O_=this->next;
            free((void *)this);
            return(1); // file closed, structure freed
         }
         else
         {
            last->next=this->next;
            free((void *)this);
            return(1); // file closed, structure freed
         }
      }

      last=this;
   }

   return(0); // invalid FH passed to FastClose()
}
//-
/// FastCloseAll
int FastCloseAll()
{
   struct FASTOPEN *next=0,*this;

   next=F_O_;

   while(next)
   {
      this=next;
      next=this->next;

      Close(this->fh);
      free((void *)this);
   }

   F_O_=0;
   return(0);
}
//-
/// FastWrite
long FastWrite(BPTR fh,void *bu,LONG size)
{
   struct FASTOPEN *next,*this;

   next=F_O_;

   while(next)
   {
      this=next;
      next=this->next;

      if(this->fh==fh)
      {
         this->size+=size;
         break;
      }
   }

   return(Write(fh,bu,size));
}
//-
/// FastClosePKT
int FastClosePKT()
{
   struct FASTOPEN *next,*this;
   char shitstring[]="xx";
   char oldfilename[50];
   char newfilename[50];
   char partialnewfilename[50];

   shitstring[0]=0;
   shitstring[1]=0;

   next=F_O_;

   while(next)
   {
      this=next;
      next=this->next;

      if(this->fh==PKTfile)
      {
         if(this->size > PKTSIZELIMIT)
         {
            strcpy(oldfilename,this->file);
            Write(this->fh,shitstring,2);
            FastClose(PKTfile);
            PKTfile=0;

            // rename the file here

            CreatePKTName(partialnewfilename);
            ASPrintf(NULL,newfilename,"OUTBOUND:%s",partialnewfilename);

            SmartRename(oldfilename,newfilename);

            strcat(bpktlogstring," | (TRC=");
            strcat(bpktlogstring,oldfilename);
            strcat(bpktlogstring,"->");
            strcat(bpktlogstring,newfilename);
            strcat(bpktlogstring,") ");
         }

         break;
      }
   }
   return(0);
}
//-
/// ClosePKT
int ClosePKT()
{
   if(PKTfile)
   FastClose(PKTfile);
   PKTfile=NULL;
   return(0);
}
//-
/// FixNumbers
USHORT FixNumbers(USHORT number)
{
   UBYTE lo;
   UBYTE hi;
   USHORT result;
   
   lo=(number & 0xff00)/256;
   hi=(number & 0x00ff);

   result=hi*256+lo;
   return(result);
}
//-
/// AddToPackets
int AddToPackets(char *start,int length,struct nodenum *outbound,int strippedlength, int waslocal,struct area *_thisarea)
{
   BOOL StripMe=FALSE;
   struct nodenum *us;

   int TOZONE,TOPOINT,fromzone,fromnet,fromnode,frompoint;

   int j,textlength,strippedtextlength;

   int ex_t=0;

   USHORT tozone,tonet,tonode,topoint;

   struct Fido_Msg_Header *bbsmsg;

   UBYTE *textstart;
   UBYTE string[200];

   char abc[100];

   if(!PKTHEADSTRUCT)
   {
      PKTHEADSTRUCT=(void *)calloc(PKTHEADLENGTH,1);

      if(!PKTHEADSTRUCT)
      {
         AFPrintf(NULL,sout,"No mem for PKTHEADSTRUCT\n");
         return(0);
      }
   }

   bbsmsg=           (void *)start;
   textstart=        (void *)(start+sizeof(struct Msg_Header));
   textlength=       length-sizeof(struct Msg_Header);
   strippedtextlength=  strippedlength-sizeof(struct Msg_Header);

   /* this will loop for every destination node in outbound list */

   if(!Strnicmp(textstart,"NOECHO",6))
   {
      AFPrintf(NULL,sout,"NOECHO\n");
      strcat(bpktlogstring,"NOECHO");
      return(0);
   }

   AFPrintf(NULL,sout,"[32m==>> [0m");

   for(;(int)outbound;outbound=outbound->next_nodenum)
   {
      
   /* we need to add code to search the *thisarea* structure's nodenum's
      until we find a match for outbound->net and outbound->node in order
      to retrieve the from information , also the tozone and topoint info */

      ex_t++;

      us=_thisarea->first_nodenum;

      do
      {
         if(outbound->zone) if(outbound->zone!=us->zone) continue;
         if(outbound->net!=us->net) continue;
         if(outbound->node!=us->node) continue;
         if(outbound->point!=us->point) continue;

         break;

      }

      while(us=us->next_nodenum);

      TOZONE      = us->zone; /* this must get the current destination zone and point ?!?! */
      TOPOINT     = us->point;

      fromzone = us->from_zone;
      fromnet     = us->from_net;
      fromnode = us->from_node;
      frompoint   = us->from_point;

      OUTBCREATED++;
      
      tozone=  (USHORT) TOZONE;  
      tonet=   (USHORT)outbound->net;
      tonode=  (USHORT)outbound->node;
      topoint=(USHORT) TOPOINT;  

      StripMe=FALSE;

      if(tozone != fromzone)
         StripMe=TRUE;

      if(us->strip) StripMe=TRUE;

      ASPrintf(NULL,abc," %d:%d/%d.%d",tozone,tonet,tonode,topoint);
      AFPrintf(NULL,sout,"[0m->[33m%-22.22s[23D",abc);
      strcat(bpktlogstring,abc);

      /* ahem... time to load up the packet structure */

      pktmsg.MsgType=   FixNumbers((USHORT)FIDOMSGTYPE);
      pktmsg.OrigNode=FixNumbers((USHORT)fromnode);
      pktmsg.DestNode=FixNumbers(tonode);
      pktmsg.OrigNet=   FixNumbers((USHORT)fromnet);  
      pktmsg.DestNet=   FixNumbers(tonet);

      pktmsg.Attribute=FixNumbers((USHORT)EXPORTATTRIB);
      pktmsg.Cost=FixNumbers((USHORT)NULL);
         strcpy(string,bbsmsg->Date);
         strcat(string,"                      ");
         string[19]=NULL;
         strcpy(pktmsg.Date,string);

      /*structure is now filled, time to append it*/

      j=OpenPKT(tozone,tonet,tonode,topoint,fromzone,fromnet,fromnode,frompoint);

      if(j)
      {
/*******************************************************************************/

         int offset;

         offset=ClearPKTStruct(PKTHEADSTRUCT,PKTHEADLENGTH);

         offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)&pktmsg,sizeof(struct PackedMsg));
   
         /* this area needs a little assistance */
   
         strcpy(string,bbsmsg->To);

         offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)string,strlen(string)+1);
   
         strcpy(string,bbsmsg->From);

         offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)string,strlen(string)+1);
   
         strcpy(string,bbsmsg->Title);

         offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)string,strlen(string)+1);
   
         strcpy(string,"AREA:");       /*tagname*/
         strcat(string,get_name(_thisarea));
         strcat(string,"\r");

         offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)string,strlen(string));

// new march 1995
         if(waslocal)
         {
            char                 MSGID[64];
            ULONG                ul;
            struct   DateStamp   ds;


            strcpy(string,"PID: DLGMail v");
            strcat(string,_VERSION);
            strcat(string,"\r");
            offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)string,strlen(string));

// new for 2.1 -- MSGID
            DateStamp(&ds);

            ul =  (ds.ds_Days * 24 * 60 * 60) + (ds.ds_Minute * 60);
            ul = ul * TICKS_PER_SECOND;
            ul = ul + ds.ds_Tick;

            Delay(2);

//            ul = AmigaTime();
            LToX(ul,MSGID);

            ASPrintf(NULL,string,"MSGID: %d:%d/%d.%d %s\r",fromzone,fromnet,fromnode,frompoint,MSGID);
            offset=AppendToPKTStruct(PKTHEADSTRUCT,offset,(void *)string,strlen(string));
// end 2.1 changes

         }
// new march 1995


         AppendToPKT((void *)PKTHEADSTRUCT,offset);

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

         
         if(StripMe==FALSE)
         {
            AppendToPKT((void *)textstart,textlength); /* message body */
         }
         else
         {
            AppendToPKT((void *)textstart,strippedtextlength);
            ASPrintf(NULL,string,"SEEN-BY: %d/%d\rPATH: %d/%d \r",fromnet,fromnode,fromnet,fromnode);
            AppendToPKT((void *)string,strlen(string));
            strcat(bpktlogstring,"=S");
         }

         strcpy(string,"");      /* ahem, null byte between messages */
         AppendToPKT((void *)string,1);

         FastClosePKT();
      }
   }

   if(ex_t>X_NTA) X_NTA=ex_t;

   AFPrintf(NULL,sout,"[32m%-22.22s[0m[18D\n"," Done");
   
   /* at this point, the message has been appended to all outbound pks */

   return(0);
}
//-
/// AppendToPKT
int AppendToPKT(UBYTE *what, int howmuch)
{
   int i;

   i=Seek(PKTfile,0,OFFSET_END); /* move to end */

   i=FastWrite(PKTfile,(void *)what,howmuch);

   if(i!=howmuch)
   {
      AFPrintf(NULL,sout,"wrote wrong number of bytes - %d",i);
   }
   return(i);
}
//-
/// OpenPKT
int OpenPKT(int zone, int net, int node, int point,int fromzone,int fromnet,int fromnode,int frompoint)
{
   int i,j;

   char pw[10];
   char use[10];
   char addr[40];

   char pktname[100];
   char filenotestring[100];

   UBYTE clock[8];

   WEXPORTED=TRUE;

   ASPrintf(NULL,pktname,"OUTBOUND:%03d.%06d.%06d.%03d.RAWPKT",zone,net,node,point);

   for(i=0;i<10;i++)
   {
      PKTfile=NULL;
      PKTfile=FastOpen(pktname,MODE_OLDFILE); /* bugfix for 2.0 */

      if(PKTfile)
      {
         return(1);
      }
      else
      {
         PKTfile=NULL;
         PKTfile=FastOpen(pktname,MODE_NEWFILE);

         if(PKTfile)
         {
            PKTSMADE++;
            strcat(bpktlogstring," (<=NEWPKT)");
   
            /* build packet header here */
            /* figure out time here */

            getclk(clock);

/*v39*/     pkthead.CapabilityWord=FixNumbers((USHORT) CAPABILITYWORD);
            pkthead.ProductCode= (UBYTE) PRODUCTCODE;
            pkthead.ProductCode_HIBYTE=0;
            pkthead.PV_Version=2;//PROGVER;
            pkthead.PV_Revision=0;//PROGREV;
            pkthead.MySerialNumber=_XORCRC;
/*v48*/     pkthead.CWValidate=(USHORT)CAPABILITYWORD;

/*v39*/     pkthead.DestZone1=   FixNumbers((USHORT)zone);
/*v39*/     pkthead.DestZone2=   FixNumbers((USHORT)zone);
            pkthead.DestNode= FixNumbers((USHORT)node);
            pkthead.DestNet=  FixNumbers((USHORT) net);
/*v39*/     pkthead.DestPoint=   FixNumbers((USHORT)point);

            pkthead.OrigZone1=   FixNumbers((USHORT)fromzone);
            pkthead.OrigZone2=   FixNumbers((USHORT)fromzone);
            pkthead.OrigNode= FixNumbers((USHORT)fromnode);
            pkthead.OrigNet=  FixNumbers((USHORT)fromnet);
            pkthead.OrigPoint=   FixNumbers((USHORT)frompoint);

            pkthead.Year=     FixNumbers((USHORT) (clock[1]+1980));
            pkthead.Month=    FixNumbers((USHORT) clock[2]-1);
            pkthead.Day=      FixNumbers((USHORT) clock[3]);
            pkthead.Hour=     FixNumbers((USHORT) clock[4]);
            pkthead.Minute=      FixNumbers((USHORT) clock[5]);
            pkthead.Second=      FixNumbers((USHORT) clock[6]);
            pkthead.Baud=0;
            pkthead.PacketType=  FixNumbers((USHORT) FIDOPKTTYPE);
            
            pkthead.Password[0]=0;
            pkthead.Password[1]=0;
            pkthead.Password[2]=0;
            pkthead.Password[3]=0;
            pkthead.Password[4]=0;
            pkthead.Password[5]=0;
            pkthead.Password[6]=0;
            pkthead.Password[7]=0;

            ASPrintf(NULL,addr,"%d:%d/%d.%d",zone,net,node,point);

            if(GetPKTPw(addr,pw,use)==1)
            {
               if(!Strnicmp(use,"OUT",3) || 0==Strnicmp(use,"BOTH",4))
               {
                  strncpy(pkthead.Password,pw,8);
                  ASPrintf(NULL,bpktlogstring,"Packet password for [%s] is [%s]",addr,pw);
               }
            }

            j=Write(PKTfile,(void *)&pkthead,sizeof(struct Packet_Header));
   
            if(j==sizeof(struct Packet_Header))
            {
               if(MyDEBUG) AFPrintf(NULL,sout,"packet header written successfully\n");
            }
            else
            {
               AFPrintf(NULL,sout,"problem writing packet header\n");
               ClosePKT();
               Delay(5);
               DeleteFile(pktname);
               Delay(5);
            }

            ClosePKT();
            
            ASPrintf(NULL,filenotestring,"%d:%d/%d.%d",zone,net,node,point);
            SetComment(pktname,filenotestring);

            /*Delay(10);*/
         }
      }
   }

   PKTfile=NULL;
   return(0);
}
//-


char LOGHELPER[20];

/// delete_all_nodenum2
void delete_all_nodenum2(struct nodenum *n)
{
  if(n==0)
    return;

  delete_all_nodenum2(n->next_nodenum);
  free((void *)n);
}
//-
/// new2
void *new2(int size)
{
  void *v;
  v=(void *)calloc(size,1);
  return(v);
}
//-
/// create_nodenum5_2
struct nodenum *create_nodenum5_2(char *org,short zone,short net,short node,short point)
{
  struct nodenum *n;

  n=new2(sizeof(struct nodenum));      // problem

  if(n==0)
    return(0);

  n->next_nodenum=0;

  stccpy(n->organization,org,MAX_STR);
  n->zone=zone;
  n->net=net;
  n->node=node;
  n->point=point;

  stccpy(n->from_organization,current_from_organization,MAX_STR);
  n->from_zone=current_from_zone;
  n->from_net=current_from_net;
  n->from_node=current_from_node;
  n->from_point=current_from_point;

  n->strip=current_strip;

  return(n);
}
//-
/// create_nodenum_on_end5_2
struct nodenum *create_nodenum_on_end5_2(struct nodenum **n,char *org,short zone,short net,short node,short point)
{
  n=get_last_nodenum_ptr(n);           //OK
  *n=create_nodenum5_2(org,zone,net,node,point);
  return(*n);
}
//-
/// create_nodenum_in_order2
struct nodenum *create_nodenum_in_order2(struct nodenum **n,short net,short node)
{
  struct nodenum *nn;

   for(;;)
   {
      if(*n==0)
      {
         *n=create_nodenum5_2("",0,net,node,0);  //problem
         return(*n);
      }

      if(net>((*n)->net) || net==((*n)->net) && node>((*n)->node))
      {
         n=&((*n)->next_nodenum);
         continue;
      }

      if(net==((*n)->net) && node==((*n)->node))
      {
         return(*n);
      }

      /* At this point, we are ready to insert... */

      nn=create_nodenum5_2("",0,net,node,0);

      if(nn)
      {
         nn->next_nodenum=*n;
         *n=nn;
         return(*n);
      }
      else
      {
         return(0);
      }
   }
}
//-
/// memreaduntilterm_SL
char *memreaduntilterm_SL(char *loc,char *buffer,char *termchars)
/* this modified to return a pointer to the null byte if the null byte hit */
{
    int i=0;
    char c;

   for(;;)
   {
      if(i++>50)
         return(NULL);

      c=*loc++;

      if(charisinstring(c,termchars) || c==NULL)
      {
         *buffer=0;    /*     ^^^^^^^^^^  modification */
         loc--;
         return(loc);
      }
      else
      {
         *buffer++=c;
      }
   }
}
//-
/// my_get_nodenum
struct nodenum *my_get_nodenum(struct areas *X,char *areaname)
{
   struct area *x;

   x=find_area_name(X,areaname);

   if(x)
      return(get_nodenum(x,1));

   return(NULL);
}
//-
/// handlemsg2
int handlemsg2(char *name, char *tagname, char *start, int *length, struct area *_thisarea)
{
   int rc=0;
   int waslocal=0;
   char originaddress[100];
   char *oa_1, *oa_2;

   BOOL topoints=FALSE;

   struct nodenum *us;

   char *pqrs, *pq, *pp;

   char *SHORTTEAR;

   struct Msg_Header *fidmsg;

   int strippedlength;
      char *originstring=" * Origin:";
      char *seenbystring="SEEN-BY:";
      char *pathstring1="PATH:";
      char *pathstring2="PATH:";
      char *loc,*temp,*seenbybeginning,*originbeginning;
      char areaname[MAXAREALEN];
      struct nodenum *seenby=0,*path=0,*area=0,*outgoing=0,*n=0,*endnode=0;
      short zone,net,node,point;
   char *organization;
   //int okay;
   int i;


   seenby=0;
   path=0;
   area=0;
   outgoing=0;
   n=0;

   strcpy(areaname,tagname);

   fidmsg=(void *)start;

   if(fidmsg->Attribute & LOCAL)
      waslocal++;

   if( (fidmsg->Attribute & SENT)==0)
      topoints=TRUE;

   loc=memsearch(start,*length,start+*length-strlen(originstring)-1,originstring,-1);
   
   /* backward search from end to find origin line. */
   
   originbeginning=loc;

   if(originbeginning)
   {
      if(MyDEBUG) AFPrintf(NULL,sout," [33mFOUND ORIGIN[0m ");
   }
   else
   {
      loc=start;
   }

//ROSS utils//
   loc=memsearch(start,*length,loc,seenbystring,1); 
                    /* search for first SEEN-BY: line */

   if(loc)     /* kludge to handle seenby's that begin with ^A */
   {
      if(MyDEBUG)
         AFPrintf(NULL,sout,"found seenby\n");

      temp=loc-1;

      if(*temp==0x01) loc--;
   }

   seenbybeginning=loc;

   if(originbeginning==NULL && seenbybeginning==NULL)    
                   /* no origin, assumed no tearline */
   {
      if(MyDEBUG)
      {
         AFPrintf(NULL,sout,"no origin & no seenby\n");
         AFPrintf(NULL,sout,"tear==%s\n",_TEAR);
         AFPrintf(NULL,sout,"origin==%s\n",_ORIGIN);
      }

      loc=stpcpy(start+*length,"\r\n");
      loc=stpcpy(loc,_TEAR);  
      loc=stpcpy(loc,"\r");
      loc=stpcpy(loc,_ORIGIN);
      *length=loc-start;
   }

   if(seenbybeginning)
   {           /*    v-- this used to be loc */

      loc=readextendednetlist(seenbybeginning,seenbystring,&seenby,_AKA1NET,_STRIPAKA1);

      if(!Strnicmp(loc,pathstring1,strlen(pathstring1)))  /* See if there is a path line. */
      {
         loc=readextendednetlist(loc,pathstring1,&path,_AKA1NET,_STRIPAKA1);
      }

      if(MyDEBUG>1)
      {
            AFPrintf(NULL,sout,"\nBefore list insertions.\n");
            AFPrintf(NULL,sout,"\nSEEN-BY LIST:\n");
            print_netnodes(seenby);
            AFPrintf(NULL,sout,"\nPATH LIST:\n");
            print_netnodes(path);
      }
   }
   else
   {
      seenbybeginning=start+*length;

      /* let's be tacky and add our tearline to DLG's */

      if((fidmsg->Attribute & 256) && originbeginning) /*local msg*/
      {
         SHORTTEAR=_TEAR;
         while(*SHORTTEAR== ' ' || *SHORTTEAR== '-')
            SHORTTEAR++;
         pqrs=originbeginning;

         while(*pqrs!='\r')
         {
            pqrs--;
         }

         pp=start+*length;
         pq=pp+strlen(SHORTTEAR)+1;

         while(pp!=pqrs)
         {
            *(pq--)=*(pp--);
         }

         *pq=*pp;
         *pqrs++='/';
         pp=SHORTTEAR;

         while(*pp)
         {
            *(pqrs++)=*(pp++);
         }

         originbeginning+=strlen(SHORTTEAR)+1;
         seenbybeginning+=strlen(SHORTTEAR)+1;
         *length+=strlen(SHORTTEAR)+1;
      }
   }

   if(seenbybeginning)
   {
      /* going to extract the address in the origin string */

      oa_1=seenbybeginning;

      for(oa_1;*oa_1!='(';oa_1--)
         ;  /* go to ( at beginning of address */
      oa_2=oa_1;  /* oa_2 points to beginning of address */
      oa_2++;


      for(oa_1;*oa_1!=')' && *oa_1!= '\r';oa_1++)
         ;  /* go to closing ) in address */
   

      i=oa_1-oa_2;

      if(i<20)
      {
         strncpy(originaddress,oa_2,i+1);
      }
      else
      {
         strcpy(originaddress,GCFG->ADDRESS[0]);
      }
   }
   else
   {
      strcpy(originaddress,GCFG->ADDRESS[0]);
   }

   area=my_get_nodenum(a,areaname); /* get list of nodes to send message on to */

    /* Now create list of sites to send the packet on to. */

   if(area)
   {
      for(n=area;n!=0;n=n->next_nodenum)
      {
         organization=n->organization;
         zone=n->zone;
         net=n->net;
         node=n->node;
         point=n->point;

         /* if we're this far, then it's ok to process points */
         if(point || (net==_AKA1NET && _STRIPAKA1))
         {
            if(_POINTENABLE==0)
            {
               if(MyDEBUG) AFPrintf(NULL,sout,"point svs not enabled\n");
               continue ;  /* forget it, we're not processing points */
            }

            if(topoints==FALSE)
            {
               if(MyDEBUG) AFPrintf(NULL,sout,"sent bit already set\n");
               continue;   /* SENT bit set */
            }

            /* figure out if the message was *from* a point
               and not try to reexport it to the same
               point again */

            if(pointtest(originaddress,zone,net,node,point,_AKA1NET))
            {
               if(MyDEBUG) AFPrintf(NULL,sout,"not exporting, we think it's the point's own message\n");

               continue;   /* pointtest returns TRUE if the orig address matches
                              the address to export to */
            }
         }

         if(is_in_nodenum_list(seenby,net,node) && point==0)
               continue;    /* skip nodes message has already been to. */

         TallyMsgs(zone,net,node,point,1);
         create_nodenum_on_end5_2(&outgoing,organization,zone,net,node,point); /* add site to outgoing list */
      }
   }

   if(outgoing)
   {
      for(n=outgoing;n!=0;n=n->next_nodenum)
      {
         /*** handle AKA strip here ***/

         if(_STRIPAKA1 && (_AKA1NET==n->net))
         {
               if(MyDEBUG) AFPrintf(NULL,sout,"not adding AKA1 address to seenby's\n");
               continue;
         }

         create_nodenum_in_order2(&seenby,get_net(n),get_node(n));
      }
   }

   /* add myself if I'm not there */

   us=_thisarea->first_nodenum;

   while(us)
   {
      if((_AKA1NET!=us->from_net) || (_STRIPAKA1==0))
      {
         create_nodenum_in_order2(&seenby,us->from_net,us->from_node);
      }
      else
      {
         if(MyDEBUG) AFPrintf(NULL,sout,"not adding our own seenby because it's our pointnet number");
      }
      us=us->next_nodenum;
   }

/* the following line reestablishes a pointer and that's it... used to add
   net/node to the path line */

   us=_thisarea->first_nodenum;

   if(outgoing && us)
   {
      MSGSPROCED++;

      if(path)
      {
         endnode=get_last_nodenum(path);
         if(MyDEBUG) AFPrintf(NULL,sout,"after get_last_nodenum()\n");

         if(!is_in_nodenum_list(endnode,us->from_net,us->from_node)) /* FIXFIXFIXFIX */
         {
            create_nodenum_on_end5_2(&path,"",0,us->from_net,us->from_node,0);   /* FIXFIXFIXFIX */ /* add local node to path */
         }
      }
      else
      {
         create_nodenum_on_end5_2(&path,"",0,us->from_net,us->from_node,0);   /* FIXFIXFIXFIX */
      }

      /* let's figure out our length if we didn't have any seenby's
         or path lines (like if we were to strip 'em for other
         zones >:-) */

      strippedlength=seenbybeginning-start;

    /* NOW, we trash the old SEEN-BY and PATH lists on our packet in */
    /* memory by rewriting the new ones on top of them. */

      if(MyDEBUG) AFPrintf(NULL,sout,"writing new seenby list\n");

      loc=writeextendednetlist(seenbybeginning,seenbystring,seenby);

      if(MyDEBUG) AFPrintf(NULL,sout,"writing new path list\n");

      loc=writeextendednetlist(loc,pathstring2,path);
      *length=loc-start;

      fidmsg->Attribute|=SENT;   /* set the sent bit for DLG */

      rc=*length;
      AFPrintf(NULL,sout," S ",name);
      ASPrintf(NULL,bpktlogstring,"[%-18s] ",name);
      AddToPackets(start,*length,outgoing,strippedlength,waslocal,_thisarea); /* <=== LINKS TO BUILDPACKETS.C */  /* calls my code to generate packets */

   /* the bpktlogstring has been appended to all during this function */

      if(_VERBOSITY>2) Log(bpktlogstring);
   }
   else
   {
      AFPrintf(NULL,sout,"No Downstream Distribution\n");   /* we aren't sending this message anywhere */
   }

   delete_all_nodenum2(seenby);
   delete_all_nodenum2(path);
   delete_all_nodenum2(outgoing);
   return(rc);
}
//-
/// pointtest
/* possible problem below when matching a pointnet node to an honest-to-got point */
/* it may match too often :-( and cause the message to be rejected */

int pointtest(char *originaddress,short zone,short net,short node,short point,int akanet)
{
   char a[5][30];
   short b[5];

   strcpy(a[0],"");
   strsfn(originaddress,a[0],a[1],a[2],a[3]);
   b[0]=atoi(a[0]);/* zone */
   b[1]=atoi(a[1]);/* net */
   b[2]=atoi(a[2]);/* node */
   b[3]=atoi(a[3]);/* point */

   if(MyDEBUG) AFPrintf(NULL,sout,"[33m%d:%d/%d.%d [0m",b[0],b[1],b[2],b[3]);

   if(net != akanet)
   {
      if(MyDEBUG) AFPrintf(NULL,sout,"test 1   ");
      if(b[1]!=net ) return(0);
      if(b[2]!=node ) return(0);
      if(b[3]!=point ) return(0);
      return(1);
   }

   if(MyDEBUG) AFPrintf(NULL,sout,"test 2   ");
   if(b[3]!=node) return(0);
   return(1);
}
//-
/// readextendednetlist
char *readextendednetlist(char *loc,char *listindstring, struct nodenum **nn,int stripthis,int ifstrip)
{
    char buffer[MAXNUMBERLEN];
    short net=0,node;

   for(;;)     /* Process a SEEN-BY: or PATH: line */
   {
      loc=memskipuntilterm(loc," "); /* Skip SEEN-BY: or PATH: */

      for(;;)    /* Process one element on SEEN-BY: or PATH: line */
      {
         loc=memskipchars(loc," ");                    /* Skip spaces */

         if(*loc=='\r' || *loc==NULL) /* << CHG >> the loc==NULL part */
            break;

         loc=memreaduntilterm_SL(loc,buffer," /\r");   /* read in first number */

         if(*loc=='/')                       /* if slash, number is net */
         {
            net=atoi(buffer);
            loc=memskipchars(loc,"/");
            loc=memreaduntilterm_SL(loc,buffer," \r"); /* read in second number */
         }

         node=atoi(buffer);         /* whatever is in buffer now is node. */

         if(ifstrip==0 || stripthis != net) 
         {
            create_nodenum_on_end5_2(nn,"",0,net,node,0);
         }

         if(*loc=='\r' || *loc==NULL) /* << CHG >> added NULL part */
            break;       /* if return termination, then look for new */
             /* SEEN-BY: at the start of the next line. */
      }

      if(*loc==NULL) break; /* << CHG >> added this */

      loc=memskipchars(loc," \r\n");

      if(Strnicmp(loc,listindstring,strlen(listindstring)))
            break;
   }

   return(loc);
}
//-
/// printoutstring
char *printoutstring(char *loc,char *string,int *linecounter)
{
    char wordbuffer[50];

    ASPrintf(NULL,wordbuffer,"%s",string); /* Add `SEEN-BY:' or `PATH:'*/
    loc=stpcpy(loc,wordbuffer);              /* to beginning of line. */
    *linecounter+=strlen(wordbuffer);         /* keep track of how much */
                    /* of line used. */
    return(loc);
}
//-
/// writeextendednetlist
char *writeextendednetlist(char *loc,char *listindstring,struct nodenum *n)
{
    short oldnet,net= -1,node;
    int linecounter=0,wordlen;
    char wordbuffer[50];

   loc=printoutstring(loc,listindstring,&linecounter);

   for(;n!=0;n=n->next_nodenum)
   {
      oldnet=net;
      net=n->net;
      node=n->node;

      if(net==oldnet)
         ASPrintf(NULL,wordbuffer," %d",node);
      else
         ASPrintf(NULL,wordbuffer," %d/%d",net,node);

      wordlen=strlen(wordbuffer);

      if(linecounter+wordlen>78)
      {
         loc=printoutstring(loc,"\r",&linecounter);
         linecounter=0;
         loc=printoutstring(loc,listindstring,&linecounter);

         ASPrintf(NULL,wordbuffer," %d/%d",net,node);
         wordlen=strlen(wordbuffer);
      }

      loc=printoutstring(loc,wordbuffer,&linecounter);
   }

   if(!Stricmp("PATH:",listindstring))
   {
      loc=printoutstring(loc," \r",&linecounter);
   }
   else
   {
         loc=printoutstring(loc,"\r",&linecounter);   
   }

   return(loc);
}
//-
 
