home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / comm / xprzedza.lzh / Zm.c < prev    next >
C/C++ Source or Header  |  1992-11-30  |  21KB  |  843 lines

  1. /**********************************************************************
  2.  *   Z M . C
  3.  *    ZMODEM protocol primitives
  4.  *    01-19-87  Chuck Forsberg Omen Technology Inc
  5.  *
  6.  * 29 July 89:
  7.  * Major overhaul by Rick Huebner for adaptation to Amiga XPR protocol spec
  8.  *
  9.  * 28 October 89:
  10.  * Converted to Lattice C 5.04
  11.  *
  12.  * 15 November 1991
  13.  * Code added to support CRC-32 by William M. Perkins.
  14.  **********************************************************************
  15.  * Modified to support ZedZap/ZedZip fidonet protocol by
  16.  * Yves Konighofer and Russel McOrmond.
  17.  *
  18.  * Adapted to xprzmodem Version 2.52 by Andrea Cisternino (30 Nov 92)
  19.  **********************************************************************/
  20.  
  21. #include <proto/all.h>
  22. #include <exec/types.h>
  23. #include <ctype.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include "xproto.h"
  27. #include "zmodem.h"
  28. #include "xprzmodem.h"
  29. #include "zcrc.h"
  30.  
  31. static char *frametypes[] =
  32. {
  33.    "Carrier Lost",         /* -3 */
  34.    "TIMEOUT",              /* -2 */
  35.    "ERROR",                /* -1 */
  36. #define FTOFFSET 3
  37.    "ZRQINIT",
  38.    "ZRINIT",
  39.    "ZSINIT",
  40.    "ZACK",
  41.    "ZFILE",
  42.    "ZSKIP",
  43.    "ZNAK",
  44.    "ZABORT",
  45.    "ZFIN",
  46.    "ZRPOS",
  47.    "ZDATA",
  48.    "ZEOF",
  49.    "ZFERR",
  50.    "ZCRC",
  51.    "ZCHALLENGE",
  52.    "ZCOMPL",
  53.    "ZCAN",
  54.    "ZFREECNT",
  55.    "ZCOMMAND",
  56.    "ZSTDERR",
  57.    "xxxxx"
  58. #define FRTYPES 22      /* Total number of frame types in this array */
  59.                         /*  not including psuedo negative entries */
  60. };
  61.  
  62. static UBYTE DLE_actions[] =
  63. {
  64.    0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 1,1,0,1,0,0,0,0, 1,0,0,0,0,0,0,0,
  65.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  66.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  67.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  68.  
  69.    0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 1,1,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,
  70.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  71.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  72.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
  73. };
  74.  
  75. /**********************************************************
  76.  * void zsbhdr(struct Vars *v, USHORT type)
  77.  *
  78.  * Send ZMODEM binary header hdr of type type
  79.  **********************************************************/
  80. void zsbhdr(struct Vars *v, USHORT type)
  81. {
  82.    UBYTE  *hdr = v->Txhdr;
  83.    short  n;
  84.    USHORT crc;
  85.    ULONG  crc32;
  86.  
  87.    xsendline(v, ZPAD);
  88.    xsendline(v, ZDLE);
  89.  
  90.    if (v->Crc32t = v->Txfcs32)   /* zsbh32() */
  91.    {
  92.       xsendline(v, ZBIN32);
  93.       zsendline(v, (UBYTE) type);
  94.  
  95. #ifdef DEBUGLOG
  96.       mysprintf(v->Msgbuf, "zsbh32: %s %lx\n", frametypes[type + FTOFFSET], v->Txpos);
  97.       dlog(v, v->Msgbuf);
  98. #endif
  99.       crc32 = 0xFFFFFFFFL;
  100.       crc32 = UPDC32(type, crc32);
  101.  
  102.       for (n = 4; --n >= 0; ++hdr)
  103.       {
  104.          crc32 = UPDC32((0377 & *hdr), crc32);
  105.          zsendline(v, *hdr);
  106.       }
  107.       crc32 = ~crc32;
  108.       for (n = 4; --n >= 0;)
  109.       {
  110.          zsendline(v, (int) crc32);
  111.          crc32 >>= 8;
  112.       }
  113.    }
  114.    else
  115.    {
  116.       xsendline(v, ZBIN);
  117.       zsendline(v, (UBYTE) type);
  118.  
  119. #ifdef DEBUGLOG
  120.       mysprintf(v->Msgbuf, "zsbhdr: %s %lx\n", frametypes[type + FTOFFSET], v->Txpos);
  121.       dlog(v, v->Msgbuf);
  122. #endif
  123.       crc = updcrc(type, 0);
  124.       for (n = 4; --n >= 0; )
  125.       {
  126.          zsendline(v, *hdr);
  127.          crc = updcrc(((USHORT) (*hdr++)), crc);
  128.       }
  129.  
  130.       crc = updcrc(((USHORT) 0), crc);
  131.       crc = updcrc(((USHORT) 0), crc);
  132.       zsendline(v, (UBYTE) (crc >> 8));
  133.       zsendline(v, (UBYTE) crc);
  134.    }
  135.  
  136. }  /* End of void zsbhdr() */
  137.  
  138. /**********************************************************
  139.  *    void zshhdr(struct Vars *v, USHORT type)
  140.  *
  141.  * Send ZMODEM HEX header hdr of type type
  142.  **********************************************************/
  143. void zshhdr(struct Vars *v, USHORT type)
  144. {
  145.    UBYTE *hdr = v->Txhdr;
  146.    short n;
  147.    USHORT crc;
  148.  
  149. #ifdef DEBUGLOG
  150.    mysprintf(v->Msgbuf, "zshhdr: %s %lx\n", frametypes[type + FTOFFSET], v->Rxbytes);
  151.    dlog(v, v->Msgbuf);
  152. #endif
  153.    sendline(v, ZPAD);
  154.    sendline(v, ZPAD);
  155.    sendline(v, ZDLE);
  156.    sendline(v, ZHEX);
  157.    zputhex(v, (UBYTE) type);
  158.    v->Crc32t = 0;
  159.  
  160.    crc = updcrc(type, 0);
  161.    for (n = 4; --n >= 0; )
  162.    {
  163.       zputhex(v, *hdr);
  164.       crc = updcrc(((USHORT) (*hdr++)), crc);
  165.    }
  166.  
  167.    crc = updcrc(((USHORT) 0), crc);
  168.    crc = updcrc(((USHORT) 0), crc);
  169.    zputhex(v, (UBYTE) (crc >> 8));
  170.    zputhex(v, (UBYTE) crc);
  171.  
  172.    /* Make it printable on remote machine */
  173.    sendline(v, '\r');
  174.    sendline(v, '\n');
  175.  
  176.    /* Uncork the remote in case a fake XOFF has stopped data flow */
  177.    if (type != ZFIN) sendline(v, XON);
  178.  
  179. }  /* End of void zshhdr() */
  180.  
  181. /**********************************************************
  182.  * void zsdata() and void zsda32()
  183.  *
  184.  * Send binary array buf of length length, with ending
  185.  * ZDLE sequence frameend
  186.  **********************************************************/
  187. void zsdata(struct Vars *v, short length, USHORT frameend)
  188. {
  189.    UBYTE  *buf, *outptr, c;
  190.    USHORT crc;
  191.    ULONG  crc32;
  192.  
  193. #ifdef DEBUGLOG
  194.    mysprintf(v->Msgbuf, v->Crc32t ? "zsda32: length=%ld end=%lx\n" 
  195.          : "zsdata: length=%ld end=%lx\n", (long) length, (long) frameend);
  196.    dlog(v, v->Msgbuf);
  197. #endif
  198.  
  199.    buf = v->Pktbuf;
  200.    outptr = v->Outbuf + v->Outbuflen;
  201.    crc32 = 0xFFFFFFFFL;    /* zsda32() */
  202.    crc = 0;
  203.  
  204.    while (--length >= 0)
  205.    {
  206.       switch (DLE_actions[c = *buf])
  207.       {
  208.          case 2:
  209.             if (v->Lastzsent != '@') goto sendit;
  210.  
  211.          /* Fallthrough */
  212.          case 1:
  213.             *outptr++ = ZDLE;
  214.             c ^= 0x40;
  215.  
  216. sendit:
  217.          case 0:
  218.             *outptr++ = v->Lastzsent = c;
  219.       }
  220.  
  221.       if (v->Crc32t)    /* zsda32() */
  222.       {
  223.          crc32 = UPDC32((0xFF & *buf++), crc32);
  224.       }
  225.       else  crc = updcrc(((USHORT) (*buf++)), crc);
  226.    }
  227.  
  228.    *outptr++ = ZDLE;
  229.    *outptr++ = frameend;
  230.    v->Outbuflen = outptr - v->Outbuf;
  231.  
  232.    if (v->Crc32t)    /* zsda32() */
  233.    {
  234.       crc32 = UPDC32(frameend, crc32);
  235.       crc32 = ~crc32;
  236.       for (length = 4; --length >= 0; )
  237.       {
  238.          zsendline(v, (int) crc32);
  239.          crc32 >>= 8;
  240.       }
  241.    }
  242.    else
  243.    {
  244.       crc = updcrc(frameend, crc);
  245.       crc = updcrc(((USHORT) 0), crc);
  246.       crc = updcrc(((USHORT) 0), crc);
  247.       zsendline(v, (UBYTE) (crc >> 8));
  248.       zsendline(v, (UBYTE) crc);
  249.    }
  250.  
  251.    if (frameend == ZCRCW) xsendline(v, XON);
  252.  
  253. }  /* End of void zsdata() */
  254.  
  255. /**********************************************************
  256.  * short zrdata(struct Vars *v, UBYTE *buf, short length)
  257.  *
  258.  * Receive array buf of max length with ending ZDLE sequence
  259.  * and CRC-16.  Returns the ending character or error code.
  260.  **********************************************************/
  261. short zrdata(struct Vars *v, UBYTE *buf, short length)
  262. {
  263.    short c, d;
  264.    USHORT crc;
  265.  
  266.    if (v->Rxframeind == ZBIN32) return zrdat32(v, buf, length);
  267.  
  268.    crc = v->Rxcount = 0;
  269.    for (;;)
  270.    {
  271.       if ((c = zdlread(v)) & ~0xFF)
  272.       {
  273. crcfoo:
  274.          switch (c)
  275.          {
  276.             case GOTCRCE:
  277.             case GOTCRCG:
  278.             case GOTCRCQ:
  279.             case GOTCRCW:
  280.                crc = updcrc(((d = c) & 0xFF), crc);
  281.                if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
  282.                crc = updcrc(c, crc);
  283.                if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
  284.                crc = updcrc(c, crc);
  285.                if (crc & 0xFFFF)
  286.                {
  287.                   strcpy(v->Msgbuf, "Bad data packet CRC-16 ");
  288.                   return ERROR;
  289.                }
  290. #ifdef DEBUGLOG
  291.             mysprintf(v->Msgbuf, "zrdata: cnt = %ld ret = %lx\n", (long) v->Rxcount, (long) d);
  292.             dlog(v, v->Msgbuf);
  293. #endif
  294.                return d;
  295.  
  296.             case GOTCAN:
  297.                strcpy(v->Msgbuf, "Transfer Cancelled (Remote Sent ZCAN");
  298.                return ZCAN;
  299.  
  300.             case TIMEOUT:
  301.                strcpy(v->Msgbuf, "Data packet timeout ");
  302.                return c;
  303.  
  304.             case RCDO:
  305.                strcpy(v->Msgbuf, "Transfer Cancelled (Remote Dropped Carrier)");
  306.                return c;
  307.  
  308.             default:
  309.                strcpy(v->Msgbuf, "Unrecognizable data packet ");
  310.                return c;
  311.  
  312.          }  /* End of "switch (c)" */
  313.       }  /* End of "if ((c = zdlread(v)) & ~0xFF)" */
  314.  
  315.       if (--length < 0) 
  316.       {
  317.          strcpy(v->Msgbuf, "Data packet too long ");
  318.          return ERROR;
  319.       }
  320.       ++v->Rxcount;
  321.       *buf++ = c;
  322.       crc = updcrc(c, crc);
  323.       continue;
  324.  
  325.    }  /* End of "for (;;)" */
  326.  
  327. }  /* End of short zrdata() */
  328.  
  329. /**********************************************************
  330.  * short zrdat32(struct Vars *v, UBYTE *buf, short length)
  331.  *
  332.  * Receive array buf of max length with ending ZDLE sequence
  333.  * and CRC-32.  Returns the ending character or error code.
  334.  **********************************************************/
  335. short zrdat32(struct Vars *v, UBYTE *buf, short length)
  336. {
  337.    short c, d;
  338.    ULONG crc32;
  339.  
  340.    crc32 = 0xFFFFFFFFL;
  341.    v->Rxcount = 0;
  342.  
  343.    for (;;)
  344.    {
  345.       if ((c = zdlread(v)) & ~0xFF)
  346.       {
  347. crcfoo:
  348.          switch (c)
  349.          {
  350.             case GOTCRCE:
  351.             case GOTCRCG:
  352.             case GOTCRCQ:
  353.             case GOTCRCW:
  354.                d = c;
  355.                c &= 0xFF;
  356.                crc32 = UPDC32(c, crc32);
  357.                if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
  358.                crc32 = UPDC32(c, crc32);
  359.                if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
  360.                crc32 = UPDC32(c, crc32);
  361.                if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
  362.                crc32 = UPDC32(c, crc32);
  363.                if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
  364.                crc32 = UPDC32(c, crc32);
  365.                if (crc32 != 0xDEBB20E3)
  366.                {
  367.                   strcpy(v->Msgbuf, "Bad data packet CRC-32 ");
  368.                   return ERROR;
  369.                }
  370. #ifdef DEBUGLOG
  371.             mysprintf(v->Msgbuf, "zrdat32: cnt = %ld ret = %lx\n", (long) v->Rxcount, (long) d);
  372.             dlog(v, v->Msgbuf);
  373. #endif
  374.                return d;
  375.  
  376.             case GOTCAN:
  377.                strcpy(v->Msgbuf, "Transfer Cancelled (Remote Sent ZCAN");
  378.                return ZCAN;
  379.  
  380.             case TIMEOUT:
  381.                strcpy(v->Msgbuf, "Data packet timeout ");
  382.                return c;
  383.  
  384.             case RCDO:
  385.                strcpy(v->Msgbuf, "Transfer Cancelled (Remote Dropped Carrier)");
  386.                return c;
  387.  
  388.             default:
  389.                strcpy(v->Msgbuf, "Unrecognizable data packet ");
  390.                return c;
  391.          }
  392.       }  /* End of "if ((c = zdlread(v)) & ~0xFF)" */
  393.  
  394.       if (--length < 0) 
  395.       {
  396.          strcpy(v->Msgbuf, "Data packet too long ");
  397.          return ERROR;
  398.       }
  399.       ++v->Rxcount;
  400.       *buf++ = c;
  401.       crc32 = UPDC32(c, crc32);
  402.       continue;
  403.  
  404.    }  /* End of "for (;;)" */
  405.  
  406. } /* End of short zrdat32() */
  407.  
  408. /**********************************************************
  409.  * short zgethdr(struct Vars *v)
  410.  *
  411.  * Read a ZMODEM header to hdr, either binary or hex.
  412.  *  On success return type of header.
  413.  *  Otherwise return negative on error.
  414.  **********************************************************/
  415. short zgethdr(struct Vars *v)
  416. {
  417.    short c, cancount;
  418.    long n;
  419. #ifdef DEBUGLOG
  420.    UBYTE msgbuf [128];
  421. #endif
  422.  
  423. /* n = v->Baud; */   /* Max characters before start of frame */
  424.  
  425.    n = KSIZE * 2;    /* We assume that since extra data may be generated */
  426.                      /* or lost due to line noise, that the maximum data */
  427.                      /* to the next header will be less than 8192 bytes. */
  428.                      /* Due to the fact that the Amiga's serial port can */
  429.                      /* loose data and thereby fall into the next header */
  430.                      /* this should allow another header to be found!    */
  431.    cancount = 5;
  432.  
  433. again:
  434.    v->Rxframeind = v->Rxtype = 0;
  435.  
  436.    switch (c = noxrd7(v))
  437.    {
  438.       case RCDO:
  439.       case TIMEOUT:
  440.          goto fifi;
  441.  
  442.       case CAN:
  443.          if (--cancount <= 0)
  444.          {
  445.             c = ZCAN;
  446.             goto fifi;
  447.          }
  448.  
  449.       default:
  450. agn2:
  451.          if (--n <= 0)
  452.          {
  453.             strcpy(v->Msgbuf, "Header search garbage count exceeded ");
  454.             return ERROR;
  455.          }
  456.          if (c != CAN) cancount = 5;
  457.          goto again;
  458.  
  459.       case ZPAD:              /* This is what we want. */
  460.          break;
  461.    }
  462.  
  463.    cancount = 5;
  464. splat:
  465.    switch (c = noxrd7(v))
  466.    {
  467.       case ZPAD:
  468.          goto splat;
  469.  
  470.       case RCDO:
  471.       case TIMEOUT:
  472.          goto fifi;
  473.  
  474.       default:
  475.          goto agn2;
  476.  
  477.       case ZDLE:              /* This is what we want. */
  478.          break;
  479.    }
  480.  
  481.    switch (c = noxrd7(v))
  482.    {
  483.       case RCDO:
  484.       case TIMEOUT:
  485.          goto fifi;
  486.  
  487.       case ZBIN:
  488.          v->Rxframeind = ZBIN;
  489.          v->Crc32 = FALSE;
  490.          c =  zrbhdr(v);
  491.          break;
  492.  
  493.       case ZBIN32:
  494.          v->Crc32 = v->Rxframeind = ZBIN32;
  495.          c =  zrbhdr32(v);
  496.          break;
  497.  
  498.       case ZHEX:
  499.          v->Rxframeind = ZHEX;
  500.          v->Crc32 = FALSE;
  501.          c =  zrhhdr(v);
  502.          break;
  503.  
  504.       case CAN:
  505.          if (--cancount <= 0)
  506.          {
  507.             c = ZCAN;
  508.             goto fifi;
  509.          }
  510.          goto agn2;
  511.  
  512.       default:
  513.          goto agn2;
  514.  
  515.    }  /* End of "switch (c = noxrd7(v))" */
  516.  
  517.    v->Rxpos = rclhdr(v);
  518. fifi:
  519.    switch (c)
  520.    {
  521.       case GOTCAN:
  522.          c = ZCAN;
  523.  
  524.       case ZNAK:
  525.       case ZCAN:
  526.       case ERROR:
  527.       case TIMEOUT:
  528.       case RCDO:
  529.          mysprintf(v->Msgbuf, "%s %s ", frametypes[c + FTOFFSET], (c >= 0) ? "header" : "error");
  530.  
  531. #ifdef DEBUGLOG
  532.       default:
  533.          if (c >= -3 && c <= FRTYPES)
  534.          {
  535.             mysprintf(msgbuf, "zgethdr: %s @ %ld\n", frametypes[c + FTOFFSET], v->Rxpos);
  536.          }
  537.          else
  538.          {
  539.             mysprintf(msgbuf, "zgethdr: Unknown type %ld @ %ld\n", (long) c, v->Rxpos);
  540.          }
  541.          dlog(v, msgbuf);
  542. #endif
  543.    }
  544.    return c;
  545.  
  546. }  /* End of short zgethdr() */
  547.  
  548. /**********************************************************
  549.  * short zrbhdr(struct Vars *v)
  550.  *
  551.  * Receive a binary style header (type and position)
  552.  **********************************************************/
  553. short zrbhdr(struct Vars *v)
  554. {
  555.    UBYTE *hdr = v->Rxhdr;
  556.    short c, n;
  557.    USHORT crc;
  558.  
  559.    if ((c = zdlread(v)) & ~0xFF) return c;
  560.    v->Rxtype = c;
  561.    crc = updcrc(c, 0);
  562.  
  563.    for (n = 4; --n >= 0; )
  564.    {
  565.       if ((c = zdlread(v)) & ~0xFF) return c;
  566.       crc = updcrc(c, crc);
  567.       *hdr++ = c;
  568.    }
  569.    if ((c = zdlread(v)) & ~0xFF) return c;
  570.    crc = updcrc(c, crc);
  571.    if ((c = zdlread(v)) & ~0xFF) return c;
  572.    crc = updcrc(c, crc);
  573.    if (crc & 0xFFFF)
  574.    {
  575.       strcpy(v->Msgbuf, "Bad Header CRC-16 ");
  576.       return ERROR;
  577.    }
  578.  
  579.    return v->Rxtype;
  580.  
  581. }  /* End of short zrbhdr() */
  582.  
  583. /**********************************************************
  584.  * short zrbhdr32(struct Vars *v)
  585.  *
  586.  * Receive a binary style header (type and position) with
  587.  * 32 bit FCS
  588.  **********************************************************/
  589. short zrbhdr32(struct Vars *v)
  590. {
  591.    UBYTE *hdr = v->Rxhdr;
  592.    short c, n;
  593.    ULONG crc32;
  594.  
  595.    if ((c = zdlread(v)) & ~0xFF) return c;
  596.    v->Rxtype = c;
  597.    crc32 = 0xFFFFFFFFL;
  598.    crc32 = UPDC32(c, crc32);
  599.  
  600. #ifdef DEBUGLOG
  601.    mysprintf(v->Msgbuf, "zrbhdr32: c=%x  crc32=%1x\n", c, crc32);
  602.    dlog(v, v->Msgbuf);
  603. #endif
  604.  
  605.    for (n = 4; --n >= 0; )
  606.    {
  607.       if ((c = zdlread(v)) & ~0xFF) return c;
  608.       crc32 = UPDC32(c, crc32);
  609.       *hdr++ = c;
  610.  
  611. #ifdef DEBUGLOG
  612.       mysprintf(v->Msgbuf, "zrbhdr32: c=%x  crc32=%1x\n", c, crc32);
  613.       dlog(v, v->Msgbuf);
  614. #endif
  615.    }
  616.  
  617.    for (n = 4; --n >= 0; )
  618.    {
  619.       if ((c = zdlread(v)) & ~0xFF) return c;
  620.       crc32 = UPDC32(c, crc32);
  621.  
  622. #ifdef DEBUGLOG
  623.       mysprintf(v->Msgbuf, "zrbhdr32: c=%x  crc32=%1x\n", c, crc32);
  624.       dlog(v, v->Msgbuf);
  625. #endif
  626.    }
  627.  
  628.    if (crc32 != 0xDEBB20E3)
  629.    {
  630.       strcpy(v->Msgbuf, "Bad Header CRC-32 ");
  631.       return ERROR;
  632.    }
  633.  
  634.    return v->Rxtype;
  635.  
  636. }  /* End of short zrbhdr32() */
  637.  
  638. /**********************************************************
  639.  * short zrhhdr(struct Vars *v)
  640.  *
  641.  * Receive a hex style header (type and position)
  642.  **********************************************************/
  643. short zrhhdr(struct Vars *v)
  644. {
  645.    UBYTE *hdr = v->Rxhdr;
  646.    short c, n;
  647.    USHORT crc;
  648.  
  649.    if ((c = zgethex(v)) < 0) return c;
  650.    v->Rxtype = c;
  651.    crc = updcrc(c, 0);
  652.  
  653.    for (n = 4; --n >= 0; )
  654.    {
  655.       if ((c = zgethex(v)) < 0) return c;
  656.       crc = updcrc(c, crc);
  657.       *hdr++ = c;
  658.    }
  659.  
  660.    if ((c = zgethex(v)) < 0) return c;
  661.    crc = updcrc(c, crc);
  662.  
  663.    if ((c = zgethex(v)) < 0) return c;
  664.    crc = updcrc(c, crc);
  665.  
  666.    if (crc & 0xFFFF)
  667.    {
  668.       strcpy(v->Msgbuf, "Bad Header CRC ");
  669.       return ERROR;
  670.    }
  671.  
  672.    if (readock(v, 1) == '\r') readock(v, 1);  /* Throw away possible cr/lf */
  673.  
  674.    return v->Rxtype;
  675.  
  676. }  /* End of short zrhhdr() */
  677.  
  678. /**********************************************************
  679.  * void zputhex(struct Vars *v, UBYTE c)
  680.  *
  681.  * Send a byte as two hex digits
  682.  **********************************************************/
  683. void zputhex(struct Vars *v, UBYTE c)
  684. {
  685.    static char digits[] = "0123456789abcdef";
  686.  
  687.    sendline(v, digits[(c >> 4) & 0x0F]);
  688.    sendline(v, digits[c & 0x0F]);
  689.  
  690. }  /* End of void zputhex() */
  691.  
  692. /**********************************************************
  693.  * void zsendline(struct Vars *v, UBYTE c)
  694.  *
  695.  * Send character c with ZMODEM escape sequence encoding.
  696.  * Escape ZDLE, real DLE, XON, XOFF, and CR following @ (Telenet net escape)
  697.  **********************************************************/
  698. void zsendline(struct Vars *v, UBYTE c)
  699. {
  700.    switch (DLE_actions[c])
  701.    {
  702.       case 2:
  703.          if (v->Lastzsent != '@') goto sendit;
  704.  
  705.          /* Fallthrough */
  706.       case 1:
  707.          xsendline(v, ZDLE);
  708.          c ^= 0x40;
  709. sendit:
  710.       case 0:
  711.          xsendline(v, v->Lastzsent = c);
  712.    }
  713.  
  714. }  /* End of void zsendline() */
  715.  
  716. /**********************************************************
  717.  * short zgethex(struct Vars *v)
  718.  *
  719.  * Decode two lower case hex digits into an 8 bit byte value
  720.  **********************************************************/
  721. short zgethex(struct Vars *v)
  722. {
  723.    short c, n;
  724.  
  725.    if ((n = noxrd7(v)) < 0) return n;
  726.    n -= '0';
  727.    if (n > 9) n -= ('a' - ':');
  728.    if (n & ~0xF) return ERROR;
  729.  
  730.    if ((c = noxrd7(v)) < 0) return c;
  731.    c -= '0';
  732.    if (c > 9) c -= ('a' - ':');
  733.    if (c & ~0xF) return ERROR;
  734.  
  735.    return (short) (n << 4 | c);
  736.  
  737. }  /* End of short zgethex() */
  738.  
  739. /**********************************************************
  740.  * short zdlread(struct Vars *v)
  741.  *
  742.  * Read a byte, checking for ZMODEM escape encoding
  743.  * including CAN*5 which represents a quick abort.
  744.  **********************************************************/
  745. short zdlread(struct Vars *v)
  746. {
  747.    short c;
  748.  
  749.    if ((c = readock(v, v->Rxtimeout)) != ZDLE) return c;
  750.    if ((c = readock(v, v->Rxtimeout)) < 0) return c;
  751.    if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0) return c;
  752.    if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0) return c;
  753.    if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0) return c;
  754.  
  755.    switch (c)
  756.    {
  757.       case CAN:
  758.          return GOTCAN;
  759.  
  760.       case ZCRCE:
  761.       case ZCRCG:
  762.       case ZCRCQ:
  763.       case ZCRCW:
  764.          return (short) (c | GOTOR);
  765.  
  766.       case ZRUB0:
  767.          return 0x7F;
  768.  
  769.       case ZRUB1:
  770.          return 0xFF;
  771.  
  772.       default:
  773.          if ((c & 0x60) ==  0x40) return (short) (c ^ 0x40);
  774.          break;
  775.    }
  776.    strcpy(v->Msgbuf, "Bad ZMODEM escape sequence ");
  777.  
  778.    return ERROR;
  779.  
  780. }  /* End of short zdlread() */
  781.  
  782. /**********************************************************
  783.  * short noxrd7(struct Vars *v)
  784.  *
  785.  * Read a character from the modem line with timeout.
  786.  * Eat parity, XON and XOFF characters.
  787.  **********************************************************/
  788. short noxrd7(struct Vars *v)
  789. {
  790.    short c;
  791.  
  792.    for (;;)
  793.    {
  794.       if ((c = readock(v, v->Rxtimeout)) < 0) return c;
  795.       switch (c &= 0x7F)
  796.       {
  797.          case XON:
  798.          case XOFF:
  799.             continue;
  800.  
  801.          default:
  802.             return c;
  803.       }
  804.    }
  805. }  /* End of short noxrd7() */
  806.  
  807. /**********************************************************
  808.  * void stohdr(struct Vars *v, long pos)
  809.  *
  810.  * Store long integer pos in Txhdr
  811.  **********************************************************/
  812. void stohdr(struct Vars *v, long pos)
  813. {
  814.    v->Txhdr[ZP0] = pos;
  815.    pos >>= 8;
  816.    v->Txhdr[ZP1] = pos;
  817.    pos >>= 8;
  818.    v->Txhdr[ZP2] = pos;
  819.    pos >>= 8;
  820.    v->Txhdr[ZP3] = pos;
  821.  
  822. }  /* End of void stohdr() */
  823.  
  824. /**********************************************************
  825.  * long rclhdr(struct Vars *v)
  826.  *
  827.  * Recover a long integer from a header
  828.  **********************************************************/
  829. long rclhdr(struct Vars *v)
  830. {
  831.    long l;
  832.  
  833.    l = v->Rxhdr[ZP3];
  834.    l = (l << 8) | v->Rxhdr[ZP2];
  835.    l = (l << 8) | v->Rxhdr[ZP1];
  836.    l = (l << 8) | v->Rxhdr[ZP0];
  837.  
  838.    return l;
  839.  
  840. }  /* End of long rclhdr() */
  841.  
  842. /* End of Zm.c source */
  843.