home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 260_01 / zm.c < prev    next >
Text File  |  1988-02-25  |  16KB  |  730 lines

  1. /*
  2.  *   Z M . C
  3.  *    ZMODEM protocol primitives
  4.  *    01-15-87  Chuck Forsberg Omen Technology Inc
  5.  *
  6.  * Entry point Functions:
  7.  *      zsbhdr(type, hdr) send binary header
  8.  *      zshhdr(type, hdr) send hex header
  9.  *      zgethdr(hdr, eflag) receive header - binary or hex
  10.  *      zsdata(buf, len, frameend) send data
  11.  *      zrdata(buf, len) receive data
  12.  *      stohdr(pos) store position data in Txhdr
  13.  *      long rclhdr(hdr) recover position offset from header
  14.  */
  15. #ifndef CANFDX
  16. #include "zmodem.h"
  17. int Rxtimeout = 100;            /* Tenths of seconds to wait for something */
  18. #endif
  19.  
  20. static char *frametypes[] =
  21.    {
  22.    "Carrier Lost",         /* -3 */
  23.    "TIMEOUT",              /* -2 */
  24.    "ERROR",                /* -1 */
  25. #define FTOFFSET 3
  26.    "ZRQINIT",
  27.    "ZRINIT",
  28.    "ZSINIT",
  29.    "ZACK",
  30.    "ZFILE",
  31.    "ZSKIP",
  32.    "ZNAK",
  33.    "ZABORT",
  34.    "ZFIN",
  35.    "ZRPOS",
  36.    "ZDATA",
  37.    "ZEOF",
  38.    "ZFERR",
  39.    "ZCRC",
  40.    "ZCHALLENGE",
  41.    "ZCOMPL",
  42.    "ZCAN",
  43.    "ZFREECNT",
  44.    "ZCOMMAND",
  45.    "ZSTDERR",
  46.    "xxxxx"
  47. #define FRTYPES 22      /* Total number of frame types in this array */
  48.                         /*  not including psuedo negative entries */
  49.    };
  50.  
  51. /* Send ZMODEM binary header hdr of type type */
  52. zsbhdr(type, hdr)
  53. char *hdr;
  54.    {
  55.    int n;
  56.    unsigned short crc;
  57.    
  58.    vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
  59.    if (type == ZDATA)
  60.       for (n = Znulls; --n >= 0; )
  61.          zsendline(0);
  62.  
  63.    xsendline(ZPAD);
  64.    xsendline(ZDLE);
  65.  
  66.    if (Txfcs32)
  67.       zsbh32(hdr, type);
  68.    else
  69.       {
  70.       xsendline(ZBIN);
  71.       zsendline(type);
  72.       crc = updcrc(type, 0);
  73.  
  74.       for (n = 4; --n >= 0; )
  75.          {
  76.          zsendline(*hdr);
  77.          crc = updcrc((0377& *hdr++), crc);
  78.          }
  79.       crc = updcrc(0,updcrc(0,crc));
  80.       zsendline(crc>>8);
  81.       zsendline(crc);
  82.       }
  83.    if (type != ZDATA)
  84.       flushmo();
  85.    }
  86.  
  87.  
  88. /* Send ZMODEM binary header hdr of type type */
  89. zsbh32(hdr, type)
  90. char *hdr;
  91.    {
  92.    int n;
  93.    unsigned long crc;
  94.  
  95.    xsendline(ZBIN32);
  96.    zsendline(type);
  97.    crc = UPDC32(type, 0xFFFFFFFF);
  98.  
  99.    for (n = 4; --n >= 0; )
  100.       {
  101.       zsendline(*hdr);
  102.       crc = UPDC32((0377& *hdr++), crc);
  103.       }
  104.    crc = ~crc;
  105.    for (n = 4; --n >= 0;)
  106.       {
  107.       zsendline(crc);
  108.       crc >>= 8;
  109.       }
  110.    }
  111.  
  112. /* Send ZMODEM HEX header hdr of type type */
  113. zshhdr(type, hdr)
  114. char *hdr;
  115.    {
  116.    int n;
  117.    unsigned short crc;
  118.  
  119.    vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
  120.    sendline(ZPAD);
  121.    sendline(ZPAD);
  122.    sendline(ZDLE);
  123.    sendline(ZHEX);
  124.    zputhex(type);
  125.  
  126.    crc = updcrc(type, 0);
  127.    for (n = 4; --n >= 0; )
  128.       {
  129.       zputhex(*hdr);
  130.       crc = updcrc((0377& *hdr++), crc);
  131.       }
  132.    crc = updcrc(0,updcrc(0,crc));
  133.    zputhex(crc>>8);
  134.    zputhex(crc);
  135.  
  136.    /* Make it printable on remote machine */
  137.    sendline(015);
  138.    sendline(012);
  139.    /*
  140.     * Uncork the remote in case a fake XOFF has stopped data flow
  141.     */
  142.    if (type != ZFIN)
  143.       sendline(021);
  144.    flushmo();
  145.    }  
  146.  
  147. /*
  148. * Send binary array buf of length length, with ending ZDLE sequence frameend
  149. */
  150. zsdata(buf, length, frameend)
  151. char *buf;
  152.    {
  153.    unsigned short crc;
  154.  
  155.    vfile("zsdata: length=%d end=%x", length, frameend);
  156.    if (Txfcs32)
  157.       zsda32(buf, length, frameend);
  158.    else
  159.       {
  160.       crc = 0;
  161.       for ( ; --length >= 0; )
  162.          {
  163.          zsendline(*buf);
  164.          crc = updcrc((0377& *buf++), crc);
  165.          }
  166.       xsendline(ZDLE);
  167.       xsendline(frameend);
  168.       crc = updcrc(frameend, crc);
  169.  
  170.       crc = updcrc(0,updcrc(0,crc));
  171.       zsendline(crc>>8);
  172.       zsendline(crc);
  173.       }
  174.    if (frameend == ZCRCW)
  175.       {
  176.       xsendline(XON);
  177.       flushmo();
  178.       }
  179.    }
  180.  
  181. zsda32(buf, length, frameend)
  182. char *buf;
  183.    {
  184.    unsigned long crc;
  185.  
  186.    crc = 0xFFFFFFFF;
  187.    for ( ;--length >= 0; )
  188.       {
  189.       zsendline(*buf);
  190.       crc = UPDC32((0377& *buf++), crc);
  191.       }
  192.    xsendline(ZDLE);
  193.    xsendline(frameend);
  194.    crc = UPDC32(frameend, crc);
  195.  
  196.    crc = ~crc;
  197.    for (length = 4; --length >= 0; )
  198.       {
  199.       zsendline(crc);
  200.       crc >>= 8;
  201.       }
  202.    }
  203.  
  204. /*
  205.  * Receive array buf of max length with ending ZDLE sequence
  206.  *  and CRC.  Returns the ending character or error code.
  207.  */
  208. zrdata(buf, length)
  209. char *buf;
  210.    {
  211.    int c;
  212.    unsigned short crc;
  213.    int d;
  214.  
  215.    if (Rxframeind == ZBIN32)
  216.       return(zrdat32(buf, length));
  217.  
  218.    crc = Rxcount = 0;
  219.    for (;;)
  220.       {
  221.       if ((c = zdlread()) & ~0377)
  222.          {
  223. crcfoo:
  224.          switch (c)
  225.             {
  226.             case GOTCRCE:
  227.             case GOTCRCG:
  228.             case GOTCRCQ:
  229.             case GOTCRCW:
  230.                crc = updcrc((d=c)&0377, crc);
  231.                if ((c = zdlread()) & ~0377)
  232.                   goto crcfoo;
  233.                crc = updcrc(c, crc);
  234.                if ((c = zdlread()) & ~0377)
  235.                   goto crcfoo;
  236.                crc = updcrc(c, crc);
  237.                if (crc & 0xFFFF)
  238.                   {
  239.                   zperr("Bad data CRC %x", crc);
  240.                   return(ERROR);
  241.                   }
  242.                vfile("zrdata: cnt = %d ret = %x", Rxcount, d);
  243.                return(d);
  244.             case GOTCAN:
  245.                zperr("ZMODEM: Sender Canceled");
  246.                return(ZCAN);
  247.             case TIMEOUT:
  248.                zperr("ZMODEM data TIMEOUT");
  249.                return(c);
  250.             default:
  251.                zperr("ZMODEM bad data subpacket ret=%x", c);
  252.                return(c);
  253.             }
  254.          }
  255.       if (--length < 0)
  256.          {
  257.          zperr("ZMODEM data subpacket too long");
  258.          return(ERROR);
  259.          }
  260.       ++Rxcount;
  261.       *buf++ = c;
  262.       crc = updcrc(c, crc);
  263.       continue;
  264.       }
  265.    }
  266.  
  267. zrdat32(buf, length)
  268. char *buf;
  269.    {
  270.    int c;
  271.    unsigned long crc;
  272.    int d;
  273.  
  274.    crc = 0xFFFFFFFF;
  275.    Rxcount = 0;
  276.    for (;;)
  277.       {
  278.       if ((c = zdlread()) & ~0377)
  279.          {
  280. crcfoo:
  281.          switch (c)
  282.             {
  283.             case GOTCRCE:
  284.             case GOTCRCG:
  285.             case GOTCRCQ:
  286.             case GOTCRCW:
  287.                crc = UPDC32((d=c)&0377, crc);
  288.                if ((c = zdlread()) & ~0377)
  289.                   goto crcfoo;
  290.                crc = UPDC32(c, crc);
  291.                if ((c = zdlread()) & ~0377)
  292.                   goto crcfoo;
  293.                crc = UPDC32(c, crc);
  294.                if ((c = zdlread()) & ~0377)
  295.                   goto crcfoo;
  296.                crc = UPDC32(c, crc);
  297.                if ((c = zdlread()) & ~0377)
  298.                   goto crcfoo;
  299.                crc = UPDC32(c, crc);
  300.                if (crc != 0xDEBB20E3)
  301.                   {
  302.                   zperr("Bad data CRC %lX", crc);
  303.                   return(ERROR);
  304.                   }
  305.                vfile("zrdat32: cnt = %d ret = %x", Rxcount, d);
  306.                return(d);
  307.             case GOTCAN:
  308.                zperr("ZMODEM: Sender Canceled");
  309.                return(ZCAN);
  310.             case TIMEOUT:
  311.                zperr("ZMODEM data TIMEOUT");
  312.                return(c);
  313.             default:
  314.                zperr("ZMODEM bad data subpacket ret=%x", c);
  315.                return(c);
  316.             }
  317.          }
  318.       if (--length < 0)
  319.          {
  320.          zperr("ZMODEM data subpacket too long");
  321.          return(ERROR);
  322.          }
  323.       ++Rxcount;
  324.       *buf++ = c;
  325.       crc = UPDC32(c, crc);
  326.       continue;
  327.       }
  328.    }
  329.  
  330.  
  331. /*
  332. * Read a ZMODEM header to hdr, either binary or hex.
  333. *  eflag controls local display of non zmodem characters:
  334. *      0:  no display
  335. *      1:  display printing characters only
  336. *      2:  display all non ZMODEM characters
  337. *  On success, set Zmodem to 1 and return type of header.
  338. *   Otherwise return negative on error
  339. */
  340. zgethdr(hdr, eflag)
  341. char *hdr;
  342.    {
  343.    int c, n, cancount;
  344.    
  345.    n = Baudrate;   /* Max characters before start of frame */
  346.    cancount = 5;
  347. again:
  348.    Rxframeind = Rxtype = 0;
  349.    switch (c = noxread7())
  350.       {
  351.       case RCDO:
  352.       case TIMEOUT:
  353.          goto fifi;
  354.       case CAN:
  355.          if (--cancount <= 0)
  356.             {
  357.             c = ZCAN;
  358.             goto fifi;
  359.             }
  360.       /* **** FALL THRU TO **** */
  361.       default:
  362. agn2:
  363.          if ( --n == 0)
  364.             {
  365.             zperr("ZMODEM Garbage count exceeded");
  366.             return(ERROR);
  367.             }
  368.          if (eflag && ((c &= 0177) & 0140))
  369.             bttyout(c);
  370.          else if (eflag > 1)
  371.             bttyout(c);
  372.          if (c != CAN)
  373.             cancount = 5;
  374.          goto again;
  375.       case ZPAD:              /* This is what we want. */
  376.          break;
  377.       }
  378.    cancount = 5;
  379. splat:
  380.    switch (c = noxread7())
  381.       {
  382.       case ZPAD:
  383.          goto splat;
  384.       case RCDO:
  385.       case TIMEOUT:
  386.          goto fifi;
  387.       default:
  388.          goto agn2;
  389.       case ZDLE:              /* This is what we want. */
  390.          break;
  391.       }
  392.  
  393.    switch (c = noxread7())
  394.       {
  395.       case RCDO:
  396.       case TIMEOUT:
  397.          goto fifi;
  398.       case ZBIN:
  399.          Rxframeind = ZBIN;
  400.          c =  zrbhdr(hdr);
  401.          break;
  402.       case ZBIN32:
  403.          Rxframeind = ZBIN32;
  404.          c =  zrbhdr32(hdr);
  405.          break;
  406.       case ZHEX:
  407.          Rxframeind = ZHEX;
  408.          c =  zrhhdr(hdr);
  409.          break;
  410.       case CAN:
  411.          if (--cancount <= 0)
  412.             {
  413.             c = ZCAN;
  414.             goto fifi;
  415.             }
  416.          goto agn2;
  417.       default:
  418.          goto agn2;
  419.       }
  420.    Rxpos = hdr[ZP3] & 0377;
  421.    Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
  422.    Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
  423.    Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
  424. fifi:
  425.    switch (c)
  426.       {
  427.       case GOTCAN:
  428.          c = ZCAN;
  429.       /* **** FALL THRU TO **** */
  430.       case ZNAK:
  431.       case ZCAN:
  432.       case ERROR:
  433.       case TIMEOUT:
  434.       case RCDO:
  435.          zperr("ZMODEM: Got %s %s", frametypes[c+FTOFFSET],
  436.                (c >= 0) ? "header" : "error");
  437.       /* **** FALL THRU TO **** */
  438.       default:
  439.          if (c >= -3 && c <= FRTYPES)
  440.             vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
  441.          else
  442.             vfile("zgethdr: %d %lx", c, Rxpos);
  443.       }
  444.    return(c);
  445.    }
  446.  
  447. /* Receive a binary style header (type and position) */
  448. zrbhdr(hdr)
  449. char *hdr;
  450.    {
  451.    int c, n;
  452.    unsigned short crc;
  453.  
  454.    if ((c = zdlread()) & ~0377)
  455.       return(c);
  456.    Rxtype = c;
  457.    crc = updcrc(c, 0);
  458.  
  459.    for (n = 4; --n >= 0; )
  460.       {
  461.       if ((c = zdlread()) & ~0377)
  462.          return(c);
  463.       crc = updcrc(c, crc);
  464.       *hdr++ = c;
  465.       }
  466.    if ((c = zdlread()) & ~0377)
  467.       return(c);
  468.    crc = updcrc(c, crc);
  469.    if ((c = zdlread()) & ~0377)
  470.       return(c);
  471.    crc = updcrc(c, crc);
  472.    if (crc & 0xFFFF)
  473.       {
  474.       zperr("Bad Header CRC");
  475.       return(ERROR);
  476.       }
  477.    Zmodem = 1;
  478.    return(Rxtype);
  479.    }
  480.  
  481. /* Receive a binary style header (type and position) with 32 bit FCS */
  482. zrbhdr32(hdr)
  483. char *hdr;
  484.    {
  485.    int c, n;
  486.    unsigned long crc;
  487.  
  488.    if ((c = zdlread()) & ~0377)
  489.       return(c);
  490.    Rxtype = c;
  491.    crc = UPDC32(c, 0xFFFFFFFF);
  492.  
  493.    for (n = 4; --n >= 0;)
  494.       {
  495.       if ((c = zdlread()) & ~0377)
  496.          return(c);
  497.       crc = UPDC32(c, crc);
  498.       *hdr++ = c;
  499.       }
  500.    for (n = 4; --n >= 0;)
  501.       {
  502.       if ((c = zdlread()) & ~0377)
  503.          return(c);
  504.       crc = UPDC32(c, crc);
  505.       }
  506.    if (crc != 0xDEBB20E3)
  507.       {
  508.       zperr("Bad Header CRC %lX", crc);
  509.       return(ERROR);
  510.       }
  511.    Zmodem = 1;
  512.    return(Rxtype);
  513.    }
  514.  
  515.  
  516. /* Receive a hex style header (type and position) */
  517. zrhhdr(hdr)
  518. char *hdr;
  519.    {
  520.    int c;
  521.    unsigned short crc;
  522.    int n;
  523.  
  524.    if ((c = zgethex()) < 0)
  525.       return(c);
  526.    Rxtype = c;
  527.    crc = updcrc(c, 0);
  528.  
  529.    for (n = 4; --n >= 0;)
  530.       {
  531.       if ((c = zgethex()) < 0)
  532.          return(c);
  533.       crc = updcrc(c, crc);
  534.       *hdr++ = c;
  535.       }
  536.    if ((c = zgethex()) < 0)
  537.       return(c);
  538.    crc = updcrc(c, crc);
  539.    if ((c = zgethex()) < 0)
  540.       return(c);
  541.    crc = updcrc(c, crc);
  542.    if (crc & 0xFFFF)
  543.       {
  544.       zperr("Bad Header CRC");
  545.       return(ERROR);
  546.       }
  547.    if (readline(1) == '\r')        /* Throw away possible cr/lf */
  548.       readline(1);
  549.    Zmodem = 1;
  550.    return(Rxtype);
  551.    }
  552.  
  553. /* Send a byte as two hex digits */
  554. zputhex(c)
  555. int c;
  556.    {
  557.    static char digits[] = "0123456789abcdef";
  558.  
  559.    if (Verbose > 4)
  560.       vfile("zputhex: %x", c);
  561.    sendline(digits[(c&0xF0)>>4]);
  562.    sendline(digits[(c)&0xF]);
  563.    }
  564.  
  565. /*
  566. * Send character c with ZMODEM escape sequence encoding.
  567. *  Escape XON, XOFF. Escape CR following @ (Telenet net escape)
  568. */
  569. zsendline(c)
  570. int c;
  571.    {
  572.    static lastsent;
  573.  
  574.    switch (c & 0377)
  575.       {
  576.       case ZDLE:
  577.          xsendline(ZDLE);
  578.          xsendline (lastsent = (c ^= 0100));
  579.          break;
  580.       case 015:
  581.       case 0215:
  582.          if ((lastsent & 0177) != '@')
  583.             goto sendit;
  584.       /* **** FALL THRU TO **** */
  585.       case 020:
  586.       case 021:
  587.       case 023:
  588.       case 0220:
  589.       case 0221:
  590.       case 0223:
  591. #ifdef ZKER
  592.          if (Zctlesc < 0)
  593.             goto sendit;
  594. #endif
  595.          xsendline(ZDLE);
  596.          c ^= 0100;
  597. sendit:
  598.          xsendline(lastsent = c);
  599.          break;
  600.       default:
  601. #ifdef ZKER
  602.          if (Zctlesc>0 && ! (c & 0140))
  603.             {
  604.             xsendline(ZDLE);
  605.             c ^= 0100;
  606.             }
  607. #endif
  608.          xsendline(lastsent = c);
  609.       }
  610.    }
  611.  
  612. /* Decode two lower case hex digits into an 8 bit byte value */
  613. zgethex()
  614.    {
  615.    int c;
  616.  
  617.    c = zgeth1();
  618.    if (Verbose > 4)
  619.       vfile("zgethex: %x", c);
  620.    return(c);
  621.    }
  622.  
  623. zgeth1()
  624.    {
  625.    int c, n;
  626.  
  627.    if ((c = noxread7()) < 0)
  628.       return(c);
  629.    n = c - '0';
  630.    if (n > 9)
  631.       n -= ('a' - ':');
  632.    if (n & ~0xF)
  633.       return(ERROR);
  634.    if ((c = noxread7()) < 0)
  635.       return(c);
  636.    c -= '0';
  637.    if (c > 9)
  638.       c -= ('a' - ':');
  639.    if (c & ~0xF)
  640.       return(ERROR);
  641.    c += (n<<4);
  642.    return(c);
  643.    }
  644.  
  645. /*
  646. * Read a byte, checking for ZMODEM escape encoding
  647. *  including CAN*5 which represents a quick abort
  648. */
  649. zdlread()
  650.    {
  651.    int c;
  652.  
  653.    if ((c = readline(Rxtimeout)) != ZDLE)
  654.       return(c);
  655.    if ((c = readline(Rxtimeout)) < 0)
  656.       return(c);
  657.    if (c == CAN && (c = readline(Rxtimeout)) < 0)
  658.       return(c);
  659.    if (c == CAN && (c = readline(Rxtimeout)) < 0)
  660.       return(c);
  661.    if (c == CAN && (c = readline(Rxtimeout)) < 0)
  662.       return(c);
  663.    switch (c)
  664.       {
  665.       case CAN:
  666.          return(GOTCAN);
  667.       case ZCRCE:
  668.       case ZCRCG:
  669.       case ZCRCQ:
  670.       case ZCRCW:
  671.          return(c | GOTOR);
  672.       case ZRUB0:
  673.          return(0177);
  674.       case ZRUB1:
  675.          return(0377);
  676.       default:
  677.          if ((c & 0140) ==  0100)
  678.             return(c ^ 0100);
  679.          break;
  680.       }
  681.    zperr("Got bad ZMODEM escape sequence %x", c);
  682.    return(ERROR);
  683.    }
  684.  
  685. /*
  686. * Read a character from the modem line with timeout.
  687. *  Eat parity, XON and XOFF characters.
  688. */
  689. noxread7()
  690.    {
  691.    int c;
  692.  
  693.    for (;;)
  694.       {
  695.       if ((c = readline(Rxtimeout)) < 0)
  696.          return(c);
  697.       switch (c &= 0177)
  698.          {
  699.          case XON:
  700.          case XOFF:
  701.             continue;
  702.          default:
  703.             return(c);
  704.          }
  705.       }
  706.    }
  707.  
  708. /* Store long integer pos in Txhdr */
  709. stohdr(pos)
  710. long pos;
  711.    {
  712.    Txhdr[ZP0] = pos;
  713.    Txhdr[ZP1] = pos>>8;
  714.    Txhdr[ZP2] = pos>>16;
  715.    Txhdr[ZP3] = pos>>24;
  716.    }
  717.  
  718. /* Recover a long integer from a header */
  719. long rclhdr(hdr)
  720. char *hdr;
  721.    {
  722.    long l;
  723.  
  724.    l = (hdr[ZP3] & 0377);
  725.    l = (l << 8) | (hdr[ZP2] & 0377);
  726.    l = (l << 8) | (hdr[ZP1] & 0377);
  727.    l = (l << 8) | (hdr[ZP0] & 0377);
  728.    return(l);
  729.    }
  730.