home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ncr9800 / ckvfn2.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  22KB  |  604 lines

  1. /*  C K v F N 2  --  System-independent Kermit protocol support functions... */
  2.  
  3. /**********************************************************************
  4. *                                                                     *
  5. * IVS / MCS-Kermit REL 2                                              *
  6. * source code                                                         *
  7. *                                                                     *
  8. * Change History:                                                     *
  9. *                                                                     *
  10. *                1. Modify C-Kermit(4E) source code to                *
  11. *                   produce new module for MCS/IVS-Kermit             *
  12. *                   ORIGINAL RELEASE                                  *
  13. *                   June 22, 1990                                     *
  14. *                                                                     *
  15. *                                                                     *
  16. ***********************************************************************/
  17.  
  18.  
  19. /*  ...Part 2 (continued from ckcfns.c)  */
  20.  
  21. /*
  22.  Author: Frank da Cruz (fdc@cunixc.cc.columbia.edu, FDCCU@CUVMA.BITNET),
  23.  Columbia University Center for Computing Activities.
  24.  First released January 1985.
  25.  Copyright (C) 1985, 1989, Trustees of Columbia University in the City of New
  26.  York.  Permission is granted to any individual or institution to use, copy, or
  27.  redistribute this software so long as it is not sold for profit, provided this
  28.  copyright notice is retained.
  29. */
  30.  
  31. /*
  32.  Note -- if you change this file, please amend the version number and date at
  33.  the top of ckcfns.c accordingly.
  34. */
  35.  
  36. #include <time.h>
  37. #include "ckcsym.h"             /* Conditional compilation (for Macintosh) */
  38. #include "ckcker.h"
  39. #include "ckcdeb.h"
  40.  
  41. extern long time();
  42. extern int     spsiz, rpsiz, timint, npad, ebq, ebqflg, rpt, rptq, rptflg,
  43.                capas;
  44. extern int     osize, pktnum, prvpkt, sndtyp, bctr, bctu, rsn, rln, maxtry,
  45.                size;
  46. extern int     maxsize, spktl, nfils, stdouf, /* warn,*/  timef, parity,
  47.                speed;
  48. extern int     turn, turnch,  delay, displa, pktlog, tralog, seslog, xflg,
  49.                mypadn, userpad;
  50. extern int     deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
  51. extern long    filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize;
  52. extern char    *cmarg, *cmarg2, **cmlist;
  53. extern CHAR    padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt;
  54. extern CHAR    filnam[], sndpkt[], recpkt[], data[], srvcmd[];
  55. extern CHAR    *srvptr, stchr, mystch, *rdatap;
  56.  
  57. char     *strcpy();                         /* Forward declarations */
  58. unsigned int     chk2();                    /* of non-int functions */
  59. unsigned int     chk3();
  60. CHAR dopar();                           /* ... */
  61.  
  62. static CHAR partab[] = {                /* Even parity table for dopar() */
  63.  
  64.      '\000', '\201', '\202', '\003', '\204', '\005', '\006', '\207',
  65.              '\210', '\011', '\012', '\213', '\014', '\215', '\216',
  66.          '\017',
  67.      '\220', '\021', '\022', '\223', '\024', '\225', '\226', '\027',
  68.              '\030', '\231', '\232', '\033', '\234', '\035', '\036',
  69.          '\237',
  70.      '\240', '\041', '\042', '\243', '\044', '\245', '\246', '\047',
  71.              '\050', '\251', '\252', '\053', '\254', '\055', '\056',
  72.          '\257',
  73.      '\060', '\261', '\262', '\063', '\264', '\065', '\066', '\267',
  74.              '\270', '\071', '\072', '\273', '\074', '\275', '\276',
  75.          '\077',
  76.      '\300', '\101', '\102', '\303', '\104', '\305', '\306', '\107',
  77.              '\110', '\311', '\312', '\113', '\314', '\115', '\116',
  78.          '\317',
  79.      '\120', '\321', '\322', '\123', '\324', '\125', '\126', '\327',
  80.              '\330', '\131', '\132', '\333', '\134', '\335', '\336',
  81.          '\137',
  82.      '\140', '\341', '\342', '\143', '\344', '\145', '\146', '\347',
  83.              '\350', '\151', '\152', '\353', '\154', '\355', '\356',
  84.          '\157',
  85.      '\360', '\161', '\162', '\363', '\164', '\365', '\366', '\167',
  86.              '\170', '\371', '\372', '\173', '\374', '\175', '\176',
  87.          '\377'
  88. };
  89.  
  90.  
  91. /* CRC generation tables */
  92.  
  93. static unsigned int     crcta[16] = {
  94.      0, 010201, 020402, 030603, 041004,
  95.      051205, 061406, 071607, 0102010, 0112211, 0122412, 0132613,
  96.          0143014,
  97.      0153215, 0163416, 0173617};
  98.  
  99.  
  100. static unsigned int     crctb[16] = {
  101.      0, 010611, 021422, 031233, 043044,
  102.      053655, 062466, 072277, 0106110, 0116701, 0127532, 0137323,
  103.      0145154, 0155745, 0164576, 0174367};
  104.  
  105.  
  106. /*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
  107.  
  108. /*
  109.  This is the function that feeds input to Kermit's finite state machine.
  110.  
  111.  If a special start state is in effect, that state is returned as if it were
  112.  the type of an incoming packet.  Otherwise:
  113.  
  114.  . If the desired packet arrives within MAXTRY tries, return its type,
  115.    with its data stored in the global 'data' array.
  116.  
  117.  . If the previous packet arrives again, resend the last packet and wait for
  118.    another to come in.
  119.  
  120.  . If the desired packet does not arrive within MAXTRY tries, return indicating
  121.    that an error packet should be sent.
  122. */
  123.  
  124. input()
  125. {
  126.      int     type, numtry;
  127.  
  128.      if (sstate != 0) {                  /* If a start state is in effect, */
  129.           type = sstate;                  /* return it like a packet type, */
  130.           sstate = 0;                     /* and then nullify it. */
  131.           return(type);
  132.      } else
  133.           type = rpack();              /* Else, try to read a packet. */
  134.  
  135.      if (deblog)
  136.           debug(F111, "input", rdatap, type);
  137.  
  138.      /* If it's the same packet we just sent, it's an echo.  Read another. */
  139.  
  140.      if (type == sndtyp)
  141.           type = rpack();
  142.  
  143.      chkint();                           /* Check for console interrupts. */
  144.      /*
  145.  If previous packet again, a timeout pseudopacket, or a bad packet, try again.
  146. */
  147.      for (numtry = 0;  (rsn == prvpkt || type == 'T' || type == 'Q' ||
  148.          type == 'N');  numtry++) {
  149.           if (numtry > maxtry) {           /* If too many tries, give up */
  150.                strcpy(data, "Timed out."); /* and send a timeout */
  151.                                            /* error packet, */
  152.                rdatap = data;              /* and pretend we read one. */
  153.                return('E');
  154.           }
  155.           if (type == 'E')
  156.                return('E');   /* Don't even bother about seq no */
  157.           if ((type == 'N') && (rsn == ((pktnum + 1) & 63))) {
  158.                /* NAK for next packet */
  159.                return('Y');                /* is ACK for current. */
  160.           } else {
  161.                resend();                   /* Else, send last packet again, */
  162.           }
  163.           if (sstate != 0) {              /* If an interrupt routine has set */
  164.                type = sstate;              /* sstate behind our back, return */
  165.                sstate = 0;                 /* that. */
  166.                *data = '\0';
  167.                return(type);
  168.           } else
  169.                type = rpack();          /* Else try to read a packet. */
  170.           chkint();                       /* Look again for interruptions. */
  171.           if (type == sndtyp)
  172.                type = rpack();
  173.      }
  174.      ttflui();                   /* Got what we want, clear input buffer. */
  175.      return(type);               /* Success, return packet type. */
  176. }
  177.  
  178.  
  179. /*  S P A C K  --  Construct and send a packet  */
  180.  
  181. /*
  182.  spack() sends a packet of the given type, sequence number n, with len
  183.  data characters pointed to by d, in either a regular or extended-
  184.  length packet, depending on length.  Returns the number of bytes
  185.  actually sent, or else -1 upon failure.  Uses global npad, padch,
  186.  mystch, bctu.  Leaves packet in null-terminated global sndpkt[] array for
  187.  later retransmission.  Updates global sndpktl (send-packet length).
  188. */
  189.  
  190. spack(type, n, len, d)
  191. char     type, *d;
  192. int     n, len;
  193. {
  194.      int     i, j, lp;
  195.      CHAR * sohp = sndpkt;
  196.      CHAR pc;
  197.      unsigned     crc;
  198.  
  199.      if (padch == 0)
  200.           padch = userpad;         /* we can not allow binary
  201.                                    zero (NULL) pad characters
  202.                                    due to the usage of the
  203.                                    string functions in mcs
  204.                                    functions.                */
  205.      if (deblog) {
  206.           debug(F100, "funct: spack", "", 0);
  207.           debug(F111, "spack", "type", type);
  208.           debug(F111, "spack", "n", n);
  209.           debug(F111, "spack", "len", len);
  210.      }
  211.  
  212.      spktl = 0;
  213.      pc = dopar(padch);                  /* The pad character, if any. */
  214.      for (i = 0; i < npad; sndpkt[i++] = pc) /* Do any requested padding */
  215.           sohp++;
  216.      sndpkt[i++] = dopar(mystch);        /* MARK */
  217.      lp = i++;                           /* Position of LEN, fill in later */
  218.      sndpkt[i++] = dopar(tochar(n));     /* SEQ field */
  219.      sndpkt[i++] = dopar(sndtyp = type); /* TYPE field */
  220.      j = len + bctu;                     /* Length of data + block check */
  221.      if (j + 2 > MAXPACK) {                /* Long packet? */
  222.           sndpkt[lp] = dopar(tochar(0));  /* Yes, set LEN to zero */
  223.           sndpkt[i++] = dopar(tochar(j / 95)); /* High part */
  224.           sndpkt[i++] = dopar(tochar(j % 95)); /* Low part */
  225.           sndpkt[i] = '\0';               /* Header checksum */
  226.           sndpkt[i++] = dopar(tochar(chk1(sndpkt + lp)));
  227.      } else
  228.           sndpkt[lp] = dopar(tochar(j + 2)); /* Normal LEN */
  229.  
  230.      if (deblog)
  231.           debug(F110, "spack: data=", d, 0);
  232.      while (len-- > 0)
  233.           sndpkt[i++] = dopar(*d++); /* Packet data */
  234.      sndpkt[i] = '\0';                   /* Null-terminate */
  235.      if (deblog)
  236.           debug(F110, "spack: packet data=", sndpkt + lp + 6, 0);
  237.  
  238.      switch (bctu) {                     /* Block check */
  239.      case 1:                         /* 1 = 6-bit chksum */
  240.           sndpkt[i++] = dopar(tochar(chk1(sndpkt + lp)));
  241.           if (deblog)
  242.                debug(F111, "spack", "checksum", sndpkt[i-1]);
  243.           break;
  244.      case 2:                         /* 2 = 12-bit chksum */
  245.           j = chk2(sndpkt + lp);
  246.           sndpkt[i++] = dopar((unsigned)tochar((j >> 6) & 077));
  247.           sndpkt[i++] = dopar((unsigned)tochar(j & 077));
  248.           break;
  249.      case 3:                         /* 3 = 16-bit CRC */
  250.           crc = chk3(sndpkt + lp);
  251.           sndpkt[i++] = dopar((unsigned)tochar(((crc & 0170000)) >>
  252.               12));
  253.           sndpkt[i++] = dopar((unsigned)tochar((crc >> 6) & 077));
  254.           sndpkt[i++] = dopar((unsigned)tochar(crc & 077));
  255.           break;
  256.      }
  257.      sndpkt[i++] = dopar(seol);          /* End of line (packet terminator) */
  258.      sndpkt[i] = '\0';                   /* Terminate string */
  259.      if (ttol(sndpkt, i) < 0)
  260.           return(-1); /* Send the packet */
  261.      spktl = i;                          /* Remember packet length */
  262.      flco += spktl;                      /* Count the characters */
  263.      tlco += spktl;
  264.      if (pktlog) {                       /* If logging packets, log it */
  265.  
  266.           long stamp;                    /* time stamp for packet logging */
  267.  
  268.           stamp = time((long *) 0);      /* get the time */
  269.           zsoutl(ZPFILE,ctime(&stamp));
  270.  
  271.           /* this for loop transforms cntl chars to their
  272.              printable form                               */
  273.  
  274.           zsout(ZPFILE, "s-");
  275.           if (*sndpkt)
  276.                zsoutl(ZPFILE,sndpkt);
  277.           else
  278.                zsoutl(ZPFILE, sohp);
  279.      }
  280.      screen(SCR_PT, type, (long)n, sohp);   /* Update screen */
  281.      return(i);                             /* Return length */
  282. }
  283.  
  284.  
  285. /*  D O P A R  --  Add an appropriate parity bit to a character  */
  286.  
  287. CHAR
  288. dopar(ch)
  289. CHAR ch;
  290. {
  291.      unsigned int     a;
  292.      if (!parity)
  293.           return(ch & 255);
  294.      else
  295.           a = ch & 127;
  296.      switch (parity) {
  297.      case 'e':
  298.           return(partab[a]);       /* Even */
  299.      case 'm':
  300.           return(a | 128);         /* Mark */
  301.      case 'o':
  302.           return(partab[a] ^ 128); /* Odd */
  303.      case 's':
  304.           return(a);               /* Space */
  305.      default:
  306.           return(a);
  307.      }
  308. }
  309.  
  310.  
  311. /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
  312.  
  313. chk1(pkt)
  314. char     *pkt;
  315. {
  316.      unsigned int     chk;
  317.      chk = chk2(pkt);
  318.      chk = (((chk & 0300) >> 6) + chk) & 077;
  319.      return(chk);
  320. }
  321.  
  322.  
  323. /*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
  324.  
  325. unsigned int
  326. chk2(pkt)
  327. CHAR *pkt;
  328. {
  329.      long     chk;
  330.      unsigned int     m;
  331.  
  332.      m = (parity) ? 0177 : 0377;
  333.      for (chk = 0; *pkt != '\0'; pkt++) {
  334.           chk += *pkt & m;
  335.      }
  336.      return(chk & 07777);
  337. }
  338.  
  339.  
  340. /*  C H K 3  --  Compute a type-3 Kermit block check.  */
  341. /*
  342.  Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
  343.  table.  Assumes the argument string contains no embedded nulls.
  344. */
  345. unsigned int
  346. chk3(pkt)
  347. CHAR *pkt;
  348. {
  349.      LONG c, crc;
  350.      unsigned int     m;
  351.      m = (parity) ? 0177 : 0377;
  352.      for (crc = 0; *pkt != '\0'; pkt++) {
  353.           c = (*pkt & m) ^ crc;
  354.           crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
  355.      }
  356.      return(crc & 0xFFFF);
  357. }
  358.  
  359.  
  360. /* Functions for sending various kinds of packets */
  361.  
  362. ack()
  363. {                                 /* Send an ordinary acknowledgment. */
  364.      spack('Y', pktnum, 0, "");             /* No data. */
  365.      nxtpkt(&pktnum);                    /* Increment the packet number. */
  366. }                                       /* Note, only call this once! */
  367.  
  368.  
  369. ack1(s)
  370. char     *s;
  371. {                      /* Send an ACK with data. */
  372.      spack('Y', pktnum, strlen(s), s);      /* Send the packet. */
  373.      nxtpkt(&pktnum);                    /* Increment the packet number. */
  374. }                                       /* Only call this once! */
  375.  
  376.  
  377. nack()
  378. {                                /* Negative acknowledgment. */
  379.      spack('N', pktnum, 0, "");             /* NAK's never have data. */
  380. }
  381.  
  382.  
  383. resend()
  384. {                              /* Send the old packet again. */
  385.      if (spktl)                          /* If buffer has something, */
  386.           ttol(sndpkt, spktl);             /* resend it, */
  387.      else
  388.           nack();                        /* otherwise send a NAK. */
  389.  
  390.      if (deblog)
  391.           debug(F111, "resend", sndpkt, spktl);
  392.      screen(SCR_PT, '%', (long)pktnum, "(resend)"); /* Say resend occurred */
  393.  
  394.      if (pktlog) {
  395.           long sstamp;                    /* time stamp for packet logging */
  396.  
  397.           sstamp = time((long *) 0);      /* get the time */
  398.           zsoutl(ZPFILE,ctime(&sstamp));
  399.  
  400.           zsout(ZPFILE, "s-");
  401.           zsoutl(ZPFILE, "(resend)"); /* Log packet if desired */
  402.      }
  403. }
  404.  
  405.  
  406. errpkt(reason)
  407. char     *reason;
  408. {          /* Send an error packet. */
  409.      encstr(reason);
  410.      spack('E', pktnum, size, data);
  411.      clsif();
  412.      clsof(1);
  413.      screen(SCR_TC, 0, 0l, "");
  414. }
  415.  
  416.  
  417. scmd(t, dat)
  418. char     t, *dat;
  419. {             /* Send a packet of the given type */
  420.      encstr(dat);                        /* Encode the command string */
  421.      spack(t, pktnum, size, data);
  422. }
  423.  
  424.  
  425. srinit()
  426. {                                        /* Send R (GET) packet */
  427.      encstr(cmarg);                      /* Encode the filename. */
  428.      spack('R', pktnum, size, data);     /* Send the packet. */
  429. }
  430.  
  431.  
  432. nxtpkt(num)
  433. int     *num;
  434. {
  435.      prvpkt = *num;                      /* Save previous */
  436.      *num = (*num + 1) % 64;             /* Increment packet number mod 64 */
  437. }
  438.  
  439.  
  440. sigint()
  441. {                              /* Terminal interrupt handler */
  442.      errpkt("User typed ^C");
  443.      doexit(GOOD_EXIT);                  /* Exit program */
  444. }
  445.  
  446.  
  447. /* R P A C K  --  Read a Packet */
  448.  
  449. /*
  450.  rpack reads a packet and returns the packet type, or else Q if the
  451.  packet was invalid, or T if a timeout occurred.  Upon successful return, sets
  452.  the values of global rsn (received sequence number),  rln (received
  453.  data length), and rdatap (pointer to null-terminated data field).
  454. */
  455. rpack()
  456. {
  457.      int     i, j, x, try, type, lp;         /* Local variables */
  458.      int     amtread, pktstart, pktlength;
  459.      unsigned     crc;
  460.      CHAR pbc[4];                        /* Packet block check */
  461.      CHAR * sohp = recpkt;               /* Pointer to SOH */
  462.      CHAR e;                             /* Packet end character */
  463.  
  464.      rsn = rln = -1;                     /* In case of failure. */
  465.      *recpkt = '\0';                     /* Clear receive buffer. */
  466.      rdatap = recpkt;                    /* Initialize this. */
  467.  
  468.      amtread = pktstart = pktlength = 0; /* Initialize */
  469.  
  470.      e = (turn) ? turnch : eol;          /* Use any handshake char for eol */
  471.  
  472.      /* Try several times to get a "line".  This allows for hosts that
  473.      echo our normal CR packet terminator as CRLF.  Don't diagnose CRLF
  474.      as an invalid packet. */
  475.  
  476. #define TTITRY 3
  477.  
  478.      for (try = 0; try < TTITRY; try++) {  /* Try x times to get a "line" */
  479.        j = ttinl(recpkt, MAXRP, timint, e);
  480.        if (j < 0) {
  481.          if (j < -1) doexit(BAD_EXIT);    /* Bail out if ^C^C typed. */
  482.          if (deblog) debug(F101, "rpack: ttinl fails", "", amtread);
  483.          screen(SCR_PT, 'T', (long)pktnum, "");
  484.          return('T');                     /* Otherwise, call it a timeout. */
  485.        }
  486.        amtread = j - 2;                   /* forget eol and null character */
  487.        tlci += amtread;                   /* All OK, Count the characters. */
  488.        flci += amtread;
  489.  
  490.        for (i = 0; (recpkt[i] != stchr) && (i < amtread); i++)
  491.          sohp++;                          /* Find mark */
  492.        pktstart = i;
  493.        if (i++ < amtread)  break;         /* Found it */
  494.      }
  495.  
  496.      if (try >= TTITRY)  return('Q');     /* Diagnose bad packet */
  497.  
  498.      lp = i;                              /* Remember LEN position. */
  499.  
  500.      if ((j = xunchar(recpkt[i++])) == 0) {    /* Long packet */
  501.        if ((j = lp + 5) > MAXRP)  return('Q');
  502.        x = recpkt[j];                     /* Header checksum. */
  503.        recpkt[j] = '\0';                  /* Calculate & compare. */
  504.        if (xunchar(x) != chk1(recpkt + lp))
  505.          return('Q');
  506.        recpkt[j] = x;                     /* Checksum ok. */
  507.        rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) -
  508.          bctu;
  509.        pktlength = rln + bctu + 6;        /* packet length */
  510.        j = 3;                             /* Data offset. */
  511.      } else if (j < 3) {
  512.           if (deblog)
  513.             debug(F101, "rpack: packet length less than 3", "", j);
  514.           return('Q');
  515.      } else {
  516.           rln = j - bctu - 2;             /* Regular packet */
  517.           pktlength = rln + bctu + 3;     /* packet length */
  518.           j = 0;                          /* No extended header */
  519.      }
  520.      rsn = xunchar(recpkt[i++]);         /* Sequence number */
  521.      type = recpkt[i++];                 /* Packet type */
  522.      i += j;                             /* Where data begins */
  523.      rdatap = recpkt + i;                /* The data itself */
  524.  
  525.      while (amtread < (pktstart + pktlength)) {
  526.         /* If we didn't initially read the entire packet, then
  527.         we'll keep reading here until we get it into the buffer. */
  528.  
  529.         j = ttinl(recpkt + amtread, MAXRP, timint, e);
  530.         if (j < 0) {                            /* bad read */
  531.           if (j < -1)  doexit(BAD_EXIT);
  532.           if (deblog)  debug(F101,"rpack: ttinl fails","",j);
  533.           return('T');
  534.         }
  535.         amtread += (j - 2);               /* bump up amount read */
  536.         tlci += (j - 2);                  /* forget eol and null */
  537.         flci += (j - 2);
  538.      }
  539.  
  540.      if (deblog)  debug(F111,"rpack: ttinl",sohp,amtread);
  541.  
  542.      if (pktlog)  {                    /* log packet if requested */
  543.         long rstamp;
  544.  
  545.         rstamp = time((long *) 0);
  546.         zsoutl(ZPFILE,ctime(&rstamp));  /* time stamp for packet */
  547.         zsout(ZPFILE,"r-");
  548.         zsoutl(ZPFILE,sohp);
  549.      }
  550.  
  551.      if ((j = rln + i) > MAXRP ) {
  552.        if (deblog)
  553.          debug(F101, "rpack: packet sticks out too far", "", j);
  554.        return('Q');
  555.      }
  556.  
  557.      for (x = 0; x < bctu; x++)          /* Copy block check */
  558.           pbc[x] = recpkt[j+x];
  559.  
  560.      pbc[x] = '\0';
  561.      recpkt[j] = '\0';                   /* Null-terminate data */
  562.  
  563.      switch (bctu) {                     /* Check the block check */
  564.      case 1:
  565.           if (xunchar(*pbc) != chk1(recpkt + lp)) {
  566.             if (deblog) {
  567.               debug(F110, "checked chars", recpkt + lp, 0);
  568.               debug(F101, "block check", "", xunchar(*pbc));
  569.               debug(F101, "should be", "", chk1(recpkt + lp));
  570.             }
  571.             return('Q');
  572.           }
  573.           break;
  574.      case 2:
  575.           x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
  576.           if (x != chk2(recpkt + lp)) {
  577.             if (deblog) {
  578.               debug(F110, "checked chars", recpkt + lp, 0);
  579.               debug(F101, "block check", "", x);
  580.               debug(F101, "should be", "", chk2(recpkt + lp));
  581.             }
  582.             return('Q');
  583.           }
  584.           break;
  585.      case 3:
  586.           crc = (xunchar(pbc[0]) << 12)
  587.            | (xunchar(pbc[1]) << 6)
  588.            | (xunchar(pbc[2]));
  589.           if (crc != chk3(recpkt + lp)) {
  590.             if (deblog) {
  591.               debug(F110, "checked chars", recpkt + lp, 0);
  592.               debug(F101, "block check", "", xunchar(*pbc));
  593.               debug(F101, "should be", "", chk3(recpkt + lp));
  594.             }
  595.             return('Q');
  596.           }
  597.           break;
  598.      default:
  599.           return('Q');
  600.      }
  601.      screen(SCR_PT, type, (long)rsn, sohp); /* Update screen */
  602.      return(type);                       /* Return packet type */
  603. }
  604.