home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / C-MODEM.ARJ / ZM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-17  |  13.0 KB  |  500 lines

  1. /*
  2.  *   Z M . C
  3.  *    ZMODEM protocol primitives
  4.  *    6-09-86  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.  
  16. #ifndef CANFDX
  17. #include "zmodem.h"
  18. int Rxtimeout = 100;            /* Tenths of seconds to wait for something */
  19. #endif
  20.  
  21. static char *frametypes[] = {
  22.         "TIMEOUT",
  23.         "ERROR",
  24.         "ZRQINIT",
  25.         "ZRINIT",
  26.         "ZSINIT",
  27.         "ZACK",
  28.         "ZFILE",
  29.         "ZSKIP",
  30.         "ZNAK",
  31.         "ZABORT",
  32.         "ZFIN",
  33.         "ZRPOS",
  34.         "ZDATA",
  35.         "ZEOF",
  36.         "ZFERR",
  37.         "ZCRC",
  38.         "ZCHALLENGE",
  39.         "ZCOMPL",
  40.         "ZCAN",
  41.         "ZFREECNT",
  42.         "ZCOMMAND",
  43.         "ZSTDERR",
  44.         "xxxxx"
  45. #define FRTYPES 22      /* Total number of frame types in this array */
  46. };
  47.  
  48. /* Send ZMODEM binary header hdr of type type */
  49. zsbhdr(type, hdr)
  50. register char *hdr;
  51. {
  52.         register n;
  53.         register unsigned short oldcrc;
  54.  
  55.         vfile("zsbhdr: %s %lx", frametypes[type+2], rclhdr(hdr));
  56.         xsendline(ZPAD); xsendline(ZDLE); xsendline(ZBIN);
  57.  
  58.         zsendline(type); oldcrc = updcrc(type, 0);
  59.  
  60.         for (n=4; --n >= 0;) {
  61.                 zsendline(*hdr);
  62.                 oldcrc = updcrc((0377& *hdr++), oldcrc);
  63.         }
  64.         oldcrc = updcrc(0,updcrc(0,oldcrc));
  65.         zsendline(oldcrc>>8);
  66.         zsendline(oldcrc);
  67.         if (type != ZDATA)
  68.                 flushmo();
  69. }
  70.  
  71. /* Send ZMODEM HEX header hdr of type type */
  72. zshhdr(type, hdr)
  73. register char *hdr;
  74. {
  75.         register n;
  76.         register unsigned short oldcrc;
  77.  
  78.         vfile("zshhdr: %s %lx", frametypes[type+2], rclhdr(hdr));
  79.         sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
  80.         zputhex(type);
  81.  
  82.         oldcrc = updcrc(type, 0);
  83.         for (n=4; --n >= 0;) {
  84.                 zputhex(*hdr); oldcrc = updcrc((0377& *hdr++), oldcrc);
  85.         }
  86.         oldcrc = updcrc(0,updcrc(0,oldcrc));
  87.         zputhex(oldcrc>>8); zputhex(oldcrc);
  88.  
  89.         /* Make it printable on remote machine */
  90.         sendline(015); sendline(012);
  91.         /*
  92.          * Uncork the remote in case a fake XOFF has stopped data flow
  93.          */
  94.         if (type != ZFIN)
  95.                 sendline(021);
  96.         flushmo();
  97. }
  98.  
  99. /*
  100.  * Send binary array buf of length length, with ending ZDLE sequence frameend
  101.  */
  102. zsdata(buf, length, frameend)
  103. register char *buf;
  104. {
  105.         register unsigned short oldcrc;
  106.  
  107.         vfile("zsdata: length=%d end=%x", length, frameend);
  108.         oldcrc = 0;
  109.         for (;--length >= 0;) {
  110.                 zsendline(*buf);
  111.                 oldcrc = updcrc((0377& *buf++), oldcrc);
  112.         }
  113.         xsendline(ZDLE); xsendline(frameend);
  114.         oldcrc = updcrc(frameend, oldcrc);
  115.  
  116.         oldcrc = updcrc(0,updcrc(0,oldcrc));
  117.         zsendline(oldcrc>>8);
  118.         zsendline(oldcrc);
  119.         if (frameend == ZCRCW) {
  120.                 xsendline(XON);  flushmo();
  121.         }
  122. }
  123.  
  124. /*
  125.  * Receive array buf of max length with ending ZDLE sequence
  126.  *  and CRC.  Returns the ending character or error code.
  127.  */
  128. zrdata(buf, length)
  129. register char *buf;
  130. {
  131.         register c;
  132.         register unsigned short oldcrc;
  133.         register d;
  134.  
  135.         oldcrc = Rxcount = 0;
  136.         for (;;) {
  137.                 if ((c = zdlread()) & ~0377) {
  138.                         switch (c) {
  139.                         case GOTCRCE:
  140.                         case GOTCRCG:
  141.                         case GOTCRCQ:
  142.                         case GOTCRCW:
  143.                                 oldcrc = updcrc((d=c)&0377, oldcrc);
  144.                                 if ((c = zdlread()) & ~0377)
  145.                                         goto badcrc;
  146.                                 oldcrc = updcrc(c, oldcrc);
  147.                                 if ((c = zdlread()) & ~0377)
  148.                                         goto badcrc;
  149.                                 oldcrc = updcrc(c, oldcrc);
  150.                                 if (oldcrc & 0xFFFF) {
  151. badcrc:
  152.                                         zperr("Bad data packet CRC");
  153.                                         return ERROR;
  154.                                 }
  155.                                 vfile("zrdata: Rxcount = %d ret = %x",
  156.                                   Rxcount, d);
  157.                                 return d;
  158.                         case GOTCAN:
  159.                                 zperr("ZMODEM: Sender Canceled");
  160.                                 return ZCAN;
  161.                         case TIMEOUT:
  162.                                 zperr("ZMODEM data packet TIMEOUT");
  163.                                 return c;
  164.                         default:
  165.                                 zperr("ZMODEM bad data packet ret=%x", c);
  166.                                 return c;
  167.                         }
  168.                 }
  169.                 if (--length < 0) {
  170.                         zperr("ZMODEM data packet too long");
  171.                         return ERROR;
  172.                 }
  173.                 ++Rxcount;
  174.                 *buf++ = c;
  175.                 oldcrc = updcrc(c, oldcrc);
  176.                 continue;
  177.         }
  178. }
  179.  
  180. /*
  181.  * Read a ZMODEM header to hdr, either binary or hex.
  182.  *  eflag controls local display of non zmodem characters:
  183.  *      0:  no display
  184.  *      1:  display printing characters only
  185.  *      2:  display all non ZMODEM characters
  186.  *  On success, set Zmodem to 1 and return type of header.
  187.  *   Otherwise return negative on error
  188.  */
  189. zgethdr(hdr, eflag)
  190. char *hdr;
  191. {
  192.         register c, n, cancount;
  193.  
  194.         n = Baudrate;   /* Max characters before start of frame */
  195.         cancount = 5;
  196. again:
  197.         Rxframeind = Rxtype = 0;
  198.         switch (c = noxread7()) {
  199.         case TIMEOUT:
  200.                 goto fifi;
  201.         case CAN:
  202.                 if (--cancount <= 0) {
  203.                         c = ZCAN; goto fifi;
  204.                 }
  205.         /* **** FALL THRU TO **** */
  206.         default:
  207. agn2:
  208.                 if ( --n == 0) {
  209.                         zperr("ZMODEM Garbage count exceeded");
  210.                         return(ERROR);
  211.                 }
  212.                 if (eflag && ((c &= 0177) & 0140))
  213.                         bttyout(c);
  214.                 else if (eflag > 1)
  215.                         bttyout(c);
  216.                 if (c != CAN)
  217.                         cancount = 5;
  218.                 goto again;
  219.         case ZPAD:              /* This is what we want. */
  220.                 break;
  221.         }
  222.         cancount = 5;
  223. splat:
  224.         switch (c = noxread7()) {
  225.         case ZPAD:
  226.                 goto splat;
  227.         case TIMEOUT:
  228.                 goto fifi;
  229.         default:
  230.                 goto agn2;
  231.         case ZDLE:              /* This is what we want. */
  232.                 break;
  233.         }
  234.  
  235.         switch (c = noxread7()) {
  236.         case TIMEOUT:
  237.                 goto fifi;
  238.         case ZBIN:
  239.                 Rxframeind = ZBIN;
  240.                 c =  zrbhdr(hdr);
  241.                 break;
  242.         case ZHEX:
  243.                 Rxframeind = ZHEX;
  244.                 c =  zrhhdr(hdr);
  245.                 break;
  246.         case CAN:
  247.                 if (--cancount <= 0) {
  248.                         c = ZCAN; goto fifi;
  249.                 }
  250.                 goto agn2;
  251.         default:
  252.                 goto agn2;
  253.         }
  254.         Rxpos = hdr[ZP3] & 0377;
  255.         Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
  256.         Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
  257.         Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
  258. fifi:
  259.         switch (c) {
  260.         case GOTCAN:
  261.                 c = ZCAN;
  262.         /* **** FALL THRU TO **** */
  263.         case ZNAK:
  264.         case ZCAN:
  265.         case ERROR:
  266.         case TIMEOUT:
  267.                 zperr("ZMODEM: Got %s %s", frametypes[c+2],
  268.                   (c >= 0) ? "header" : "error");
  269.         /* **** FALL THRU TO **** */
  270.         default:
  271.                 if (c >= -2 && c <= FRTYPES)
  272.                         vfile("zgethdr: %s %lx", frametypes[c+2], Rxpos);
  273.                 else
  274.                         vfile("zgethdr: %d %lx", c, Rxpos);
  275.         }
  276.         return c;
  277. }
  278.  
  279. /* Receive a binary style header (type and position) */
  280. zrbhdr(hdr)
  281. register char *hdr;
  282. {
  283.         register c, n;
  284.         register unsigned short oldcrc;
  285.  
  286.         if ((c = zdlread()) & ~0377)
  287.                 return c;
  288.         Rxtype = c;
  289.         oldcrc = updcrc(c, 0);
  290.  
  291.         for (n=4; --n >= 0;) {
  292.                 if ((c = zdlread()) & ~0377)
  293.                         return c;
  294.                 oldcrc = updcrc(c, oldcrc);
  295.                 *hdr++ = c;
  296.         }
  297.         if ((c = zdlread()) & ~0377)
  298.                 return c;
  299.         oldcrc = updcrc(c, oldcrc);
  300.         if ((c = zdlread()) & ~0377)
  301.                 return c;
  302.         oldcrc = updcrc(c, oldcrc);
  303.         if (oldcrc & 0xFFFF) {
  304.                 zperr("Bad Header CRC"); return ERROR;
  305.         }
  306.         Zmodem = 1;
  307.         return Rxtype;
  308. }
  309.  
  310. /* Receive a hex style header (type and position) */
  311. zrhhdr(hdr)
  312. char *hdr;
  313. {
  314.         register c;
  315.         register unsigned short oldcrc;
  316.         register n;
  317.  
  318.         if ((c = zgethex()) < 0)
  319.                 return c;
  320.         Rxtype = c;
  321.         oldcrc = updcrc(c, 0);
  322.  
  323.         for (n=4; --n >= 0;) {
  324.                 if ((c = zgethex()) < 0)
  325.                         return c;
  326.                 oldcrc = updcrc(c, oldcrc);
  327.                 *hdr++ = c;
  328.         }
  329.         if ((c = zgethex()) < 0)
  330.                 return c;
  331.         oldcrc = updcrc(c, oldcrc);
  332.         if ((c = zgethex()) < 0)
  333.                 return c;
  334.         oldcrc = updcrc(c, oldcrc);
  335.         if (oldcrc & 0xFFFF) {
  336.                 zperr("Bad Header CRC"); return ERROR;
  337.         }
  338.         if (readline(1) == '\r')        /* Throw away possible cr/lf */
  339.                 readline(1);
  340.         Zmodem = 1; return Rxtype;
  341. }
  342.  
  343. /* Send a byte as two hex digits */
  344. zputhex(c)
  345. register c;
  346. {
  347.         static char     digits[]        = "0123456789abcdef";
  348.  
  349.         if (Verbose>4)
  350.                 vfile("zputhex: %x", c);
  351.         sendline(digits[(c&0xF0)>>4]);
  352.         sendline(digits[(c)&0xF]);
  353. }
  354.  
  355. /*
  356.  * Send character c with ZMODEM escape sequence encoding.
  357.  *  Escape XON, XOFF. Escape CR following @ (Telenet net escape)
  358.  */
  359. zsendline(c)
  360. register c;
  361. {
  362.         static lastsent;
  363.  
  364.         switch (c & 0377) {
  365.         case 015:
  366.         case 0215:
  367.                 if ((lastsent & 0177) != '@')
  368.                         goto sendit;
  369.         /* **** FALL THRU TO **** */
  370.         case ZDLE:
  371.         case 021:
  372.         case 023:
  373.         case 0221:
  374.         case 0223:
  375.                 xsendline(ZDLE);
  376.                 c ^= 0100;
  377.         /* **** FALL THRU TO **** */
  378. sendit:
  379.         default:
  380.                 xsendline(lastsent = c);
  381.         }
  382. }
  383.  
  384. /* Decode two lower case hex digits into an 8 bit byte value */
  385. zgethex()
  386. {
  387.         register c;
  388.  
  389.         c = zgeth1();
  390.         if (Verbose>4)
  391.                 vfile("zgethex: %x", c);
  392.         return c;
  393. }
  394. zgeth1()
  395. {
  396.         register c, n;
  397.  
  398.         if ((c = noxread7()) < 0)
  399.                 return c;
  400.         n = c - '0';
  401.         if (n > 9)
  402.                 n -= ('a' - ':');
  403.         if (n & ~0xF)
  404.                 return ERROR;
  405.         if ((c = noxread7()) < 0)
  406.                 return c;
  407.         c -= '0';
  408.         if (c > 9)
  409.                 c -= ('a' - ':');
  410.         if (c & ~0xF)
  411.                 return ERROR;
  412.         c += (n<<4);
  413.         return c;
  414. }
  415.  
  416. /*
  417.  * Read a byte, checking for ZMODEM escape encoding
  418.  *  including CAN*5 which represents a quick abort
  419.  */
  420. zdlread()
  421. {
  422.         register c;
  423.  
  424.         if ((c = readline(Rxtimeout)) != ZDLE)
  425.                 return c;
  426.         if ((c = readline(Rxtimeout)) < 0)
  427.                 return c;
  428.         if (c == CAN && (c = readline(Rxtimeout)) < 0)
  429.                 return c;
  430.         if (c == CAN && (c = readline(Rxtimeout)) < 0)
  431.                 return c;
  432.         if (c == CAN && (c = readline(Rxtimeout)) < 0)
  433.                 return c;
  434.         switch (c) {
  435.         case CAN:
  436.                 return GOTCAN;
  437.         case ZCRCE:
  438.         case ZCRCG:
  439.         case ZCRCQ:
  440.         case ZCRCW:
  441.                 return (c | GOTOR);
  442.         case ZRUB0:
  443.                 return 0177;
  444.         case ZRUB1:
  445.                 return 0377;
  446.         default:
  447.                 if ((c & 0140) ==  0100)
  448.                         return (c ^ 0100);
  449.                 break;
  450.         }
  451.         zperr("Got bad ZMODEM escape sequence %x", c);
  452.         return ERROR;
  453. }
  454.  
  455. /*
  456.  * Read a character from the modem line with timeout.
  457.  *  Eat parity, XON and XOFF characters.
  458.  */
  459. noxread7()
  460. {
  461.         register c;
  462.  
  463.         for (;;) {
  464.                 if ((c = readline(Rxtimeout)) < 0)
  465.                         return c;
  466.                 switch (c &= 0177) {
  467.                 case XON:
  468.                 case XOFF:
  469.                         continue;
  470.                 default:
  471.                         return c;
  472.                 }
  473.         }
  474. }
  475.  
  476. /* Store long integer pos in Txhdr */
  477. stohdr(pos)
  478. long pos;
  479. {
  480.         Txhdr[ZP0] = pos;
  481.         Txhdr[ZP1] = pos>>8;
  482.         Txhdr[ZP2] = pos>>16;
  483.         Txhdr[ZP3] = pos>>24;
  484. }
  485.  
  486. /* Recover a long integer from a header */
  487. long
  488. rclhdr(hdr)
  489. register char *hdr;
  490. {
  491.         register long l;
  492.  
  493.         l = (hdr[ZP3] & 0377);
  494.         l = (l << 8) | (hdr[ZP2] & 0377);
  495.         l = (l << 8) | (hdr[ZP1] & 0377);
  496.         l = (l << 8) | (hdr[ZP0] & 0377);
  497.         return l;
  498. }
  499.  
  500.