#include "ufk.h"
#include <setjmp.h>

jmp_buf rp_env;

/*
 *  s p a c k
 *
 *  Send a Packet
 */

spack(type,num,len,data,offset,check)
char  type, *data,
      num, check;
int   len,
      offset;
{
   int   i;                               /* Temporary variable */
   char  buffer[7];                       /* Packet help buffer */
   unsigned int crc, chksum, ck1, ck2, ck3,/* CRC value and checksum */
                calc_crc();
   register char *p, *bufp;               /* Buffer pointer */
   char *q;                               /* Temp pointer */

   prtdbgf("Packet transmitted: %d, Type: %c, Length: %d\n",num,type,len);
   if (!remote && !nooutput)
   {
      if (screen)
      {
         posit(20,7);
         printf("%2d",num);
      }
      else
         printf("Xmit: %d\r",num);
   }
   if (debug)                       /* Display outgoing packet */
   {
      if (screen)
      {
         clreol(0,12);              /* Clear out data area */
         clreol(20,11);
      }
      if ((debug >= 1) && !remote)
      {
         if (screen)
         {
            posit(33,7);
            printf("%c",type);
            posit(45,7);
            printf("%4d",len);
         }
         else
            printf("Type: %c Length: %d\n\l",type,len);
      }
      if (len != 0)
      {
         if ((debug >= 1) && !remote)
         {
            if (screen)
            {
               posit(20,11);
               printf("\"%.58s\"",&data[offset]);
               if (len > 58)
               {
                  posit(20,12);
                  printf("\"%.58s\"",&data[58+offset]);
               }
            }
            else
               printf("Data transmitted: \"%.94s\"\n\l",&data[offset]);
         }
         prtdbgf("Data transmitted: \"%.94s\"\n",data);
      }
   }

   purgeline(ttyfd);                      /* Eat old input */
   if (sflg || rflg)
      pack_sent++;                        /* Count packet */
   bufp = buffer;                         /* Set up buffer pointer */

   zero_crc();                            /* Initialize CRC calculation */
   *bufp++ = mypackstart;                 /* Packet marker */
   if (len > 91)
      i = 0;                              /* Use long packet format */
   else
      i = len + check + 2;                /* Use normal length */
   *bufp++ = tochar(i);                   /* Send the character count */
   chksum  = tochar(i);                   /* Initialize the checksum */
   calc_crc(tochar(i));                   /* Calculate CRC */
   *bufp++ = tochar(num);                 /* Packet number */
   chksum += tochar(num);                 /* Update checksum */
   calc_crc(tochar(num));                 /* Calculate CRC */
   *bufp++ = type;                        /* Packet type */
   chksum += type;                        /* Update checksum */
   crc = calc_crc(type);                  /* Calculate CRC */
   if (i == 0)
   {
      i = len + check;            /* account for header and normal checksum */
      *bufp = tochar(i / 95);
      chksum += *bufp;                    /* Update checksum */
      calc_crc(*bufp++);                  /* Calculate CRC */
      *bufp = tochar(i % 95);
      chksum += *bufp;                    /* Update checksum */
      calc_crc(*bufp++);                  /* Calculate CRC */
      *bufp = tochar((chksum+((chksum & 0300) >> 6)) & 077);/* Hdr checksum */
      chksum += *bufp;                    /* Update checksum */
      crc = calc_crc(*bufp++);            /* Calculate CRC */
   }
   if ((type == 'N') && (sflg || rflg))
      nak_sent++;                         /* Count nak */

   p = data + offset;
   q = p + len;
   while (p < q)                          /* Loop for all data characters */
   {
      chksum += (unsigned char) *p;       /* Update checksum */
      crc = calc_crc(*p++);               /* Calculate CRC */
   }
   chksum &= 0x0fff;                      /* Prevent overflow */
   for (i = 0;i < pad; i++)
      kwrite(ttyfd,&padchar,1);           /* Issue any padding */
   kwrite(ttyfd,buffer,bufp-buffer);      /* Send start of packet */
   if (len != 0)
      kwrite(ttyfd, &data[offset], len);  /* Send the data if any */
   bufp = buffer;                         /* Reset pointer */
   switch (check)
   {
      case 1:                             /* One character checksum */
              chksum = (((chksum & 0300) >> 6) + chksum) & 077;
              *bufp++ = (ck1 = tochar(chksum)); /* Put it in the packet */
              break;
      case 2:                             /* Two character checksum */
              *bufp++ = (ck1 = tochar((chksum >> 6) & 077));
              *bufp++ = (ck2 = tochar(chksum & 077));
              break;
      case 3:                             /* Three character CRC */
              *bufp++ = (ck1 = tochar((crc >> 12) & 017));
              *bufp++ = (ck2 = tochar((crc >> 6) & 077));
              *bufp++ = (ck3 = tochar(crc & 077));
   }
   *bufp++ = eol;                         /* Extra-packet line terminator */
   kwrite(ttyfd, buffer,bufp-buffer);     /* Send the rest of the packet */
   if (sflg || rflg)
      dchr_sent += len;                   /* Adjust character counters */

   if (debug)
   {
      if (debug >= 1)
         if (screen)
            posit(60,7);
         else
            fputs("Checksum: ",stdout);
      prtdbgf("Checksum: ");
      switch(check)
      {
         case 1:
               prtdbg("%02x\n",unchar(ck1));
               break;
         case 2:
               prtdbg("%02x%02x\n",unchar(ck1),unchar(ck2));
               break;
         case 3:
               prtdbg("%02x%02x%02x\n",unchar(ck1),unchar(ck2),unchar(ck3));
      }
      if (!screen)
         fputs("\l",stdout);
   }
   if (sflg)
      disp_size_transferred();            /* Show how far we've got */
}

/*
 *  r p a c k
 *
 *  Read a Packet
 */

rpack(len,num,data,check)
char  *num, check,                        /* number, checksum type */
      *data;                              /* Packet data */
int   *len;                               /* Length */
{
   int   done,
         s;
   unsigned int cchksum,                  /* Checksums */
         rchksum,
         ck1, ck2, ck3,
         crc;                             /* and CRC */
   char  t,                               /* Current input character */
         type,                            /* Packet type */
         type0,                           /* Type 0 packet type */
         *p;

   do                                     /* Wait for packet header */
   {
      if (kread(ttyfd,&t,1) == TIMEOUT)
         return ('T');                    /* Return timeout */
      t &= 0177;                          /* Handle parity */
   }
   while (t != mypackstart);

   done = FALSE;                          /* Got packet start, init loop */
   while (!done)                          /* Loop to get a packet */
   {
      if (setjmp(rp_env))
         return('T');                     /* Return if timeout */
      zero_crc();                         /* Start new CRC calculation */
      cchksum = 0;
      if (getpck(&t,&cchksum,&crc))
         continue;                        /* Resynch if start of packet */

      if (unchar(t) == 0)
         type0 = TRUE;                    /* Type 0 extended header */
      else if ((unchar(t) == 1) ||
               (unchar(t) == 2))
         return(FALSE);                   /* Invalid packet length */
      else
      {
         type0 = FALSE;
         *len = unchar(t)-check-2;        /* Character count */
      }
      if (getpck(&t,&cchksum,&crc))
         continue;                        /* Resynch if start of packet */
      *num = unchar(t);                   /* Packet number */

      if (getpck(&t,&cchksum,&crc))
         continue;                        /* Resynch if start of packet */
      type = t;                           /* Packet type */
      if ((type == 'N') && (sflg || rflg))
         nak_rec++;                       /* Count received nak */

      if (type0)
      {
         if (getpck(&t,&cchksum,&crc))
            continue;                     /* Resynch if start of packet */
         *len = 95 * unchar(t);           /* First part of length */
         if (getpck(&t,&cchksum,&crc))
            continue;                     /* Resynch if start of packet */
         *len += unchar(t);               /* Second part of length */
         *len -= check;                   /* Correction */
         s = cchksum;
         if (getpck(&t,&cchksum,&crc))
            continue;                     /* Resynch if start of packet */
         if (t != tochar((s + ((s & 0300) >> 6)) & 077))
            return(FALSE);                /* Header checksum error */
      }
      p = data;
      while (p < data + *len)             /* The data itself, if any */
      {                                   /* Loop for character count */
         if (kread(ttyfd,&t,1) == TIMEOUT)/* Get character */
            return ('T');
         if (!binfil)                     /* Handle parity */
            t &= 0177;
         if (t == mypackstart)            /* Resynch if start of packet */
            continue;
         cchksum += (unsigned char) t;    /* Update checksum */
         crc = calc_crc(t);               /* Calculate CRC */
         *p++ = t;                        /* Put it in the data buffer */
      }
      cchksum &= 0x0fff;                  /* Prevent overflow */
      *p = '\0';                          /* Mark the end of the data */

      if (kread(ttyfd,&t,1) == TIMEOUT)   /* Get character */
         return ('T');
      if (check == 1)
         rchksum = (ck1 = unchar(t));     /* Convert to numeric */
      else if (check == 2)
      {
         rchksum = (ck1 = unchar(t)) << 6;
         if (kread(ttyfd,&t,1) == TIMEOUT)/* Get character */
            return ('T');
         rchksum += (ck2 = unchar(t));
      }
      else if (check == 3)
      {
         rchksum = (ck1 = unchar(t)) << 12;
         if (kread(ttyfd,&t,1) == TIMEOUT)/* Get character */
            return ('T');
         rchksum += (ck2 = unchar(t)) << 6;
         if (kread(ttyfd,&t,1) == TIMEOUT)/* Get character */
            return ('T');
         rchksum += (ck3 = unchar(t));
      }
      if (kread(ttyfd,&t,1) == TIMEOUT)   /* get EOL character and toss it */
         return ('T');
      t &= 0177;                          /* Handle parity */
      if (t == mypackstart)               /* Resynch if start of packet */
         continue;
      done = TRUE;                        /* Got checksum, done */
   }

   if (sflg || rflg)
   {
      dchr_rec += *len;                   /* Count received data characters */
      pack_rec++;                         /* Count packet */
   }
   if (check == 3)
      cchksum = crc;                      /* Set calculated value */
   else if (check == 2)
      cchksum &= 07777;                   /* Strip result to 12 bits */
   if (check == 1)
      cchksum = (((cchksum & 0300) >> 6) + cchksum) & 077; /* Final checksum */

   prtdbgf("Packet received: %d, Type: %c, Length: %d\n",*num,type,*len);
   if (!remote && !nooutput)
   {
      if (screen)
      {
         posit(20,6);
         printf("%2d",*num);
      }
      else
         printf("Rcv:  %d\r",*num);
   }
   if (debug)                             /* Display incoming packet */
   {
      if ((debug >= 1) && !remote)
      {
         if (screen)
         {
            posit(33,6);
            printf("%c",type);
            posit(45,6);
            printf("%4d",*len);
            posit(60,6);
         }
         else
            printf("Type: %c Length: %d\n\l",type,*len);
      }
      prtdbgf("Checksum: ");
      if (!screen)
         fputs("Checksum: ",stdout);
      switch(check)
      {
         case 1:
               prtdbg("%02x\n",ck1);
               break;
         case 2:
               prtdbg("%02x%02x\n",ck1,ck2);
               break;
         case 3:
               prtdbg("%02x%02x%02x\n",ck1,ck2,ck3);
      }
      if (!screen)
         fputs("\l",stdout);
      if (screen)
      {
         clreol(20,9);
         clreol(0,10);
      }
      if (*len != 0)
      {
         if ((debug >= 1) && !remote)
         {
            if (screen)
            {
               posit(20,9);
               printf("\"%.58s\"",data);
               if (*len > 58)
               {
                  posit(20,10);
                  printf("\"%.58s\"",&data[58]);
               }
            }
            else
               printf("Data received: \"%.94s\"\n\l",data);
         }
         prtdbgf("Data received: \"%.94s\"\n",data);
      }
   }

   if (rflg)
      disp_size_transferred();            /* Show how far we've got */
   if (cchksum != rchksum)
      return(FALSE);                      /* Checksum error */
   else
      return(type);                       /* All OK, return packet type */
}

getpck(t,cks,crc)
char *t;
unsigned int *cks,*crc;
{
   if (kread(ttyfd,t,1) == TIMEOUT)       /* Get character */
      longjmp(rp_env,TRUE);
   *t &= 0177;                            /* Handle parity */
   *cks &= 0x0fff;                        /* Prevent overflow */
   *cks += *t;                            /* Update checksum */
   *crc = calc_crc(*t);                   /* Calculate CRC */
   if (*t == mypackstart)
      return(TRUE);                       /* New start of packet received */
   else
      return(FALSE);
}
