home *** CD-ROM | disk | FTP | other *** search
- /*
- * Z M . C
- * ZMODEM protocol primitives
- * 01-19-87 Chuck Forsberg Omen Technology Inc
- *
- * 29 July 89:
- * Major overhaul by Rick Huebner for adaptation to Amiga XPR protocol spec
- *
- * 28 October 89:
- * Converted to Lattice C 5.04
- */
-
-
- #include <proto/all.h>
- #include <exec/types.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
- #include "xproto.h"
- #include "zmodem.h"
- #include "xprzmodem.h"
- #include "zcrc.h"
-
-
- static char *frametypes[] = {
- "Carrier Lost", /* -3 */
- "TIMEOUT", /* -2 */
- "ERROR", /* -1 */
- #define FTOFFSET 3
- "ZRQINIT",
- "ZRINIT",
- "ZSINIT",
- "ZACK",
- "ZFILE",
- "ZSKIP",
- "ZNAK",
- "ZABORT",
- "ZFIN",
- "ZRPOS",
- "ZDATA",
- "ZEOF",
- "ZFERR",
- "ZCRC",
- "ZCHALLENGE",
- "ZCOMPL",
- "ZCAN",
- "ZFREECNT",
- "ZCOMMAND",
- "ZSTDERR",
- "xxxxx"
- #define FRTYPES 22 /* Total number of frame types in this array */
- /* not including psuedo negative entries */
- };
-
-
- /* Send ZMODEM binary header hdr of type type */
- void zsbhdr(struct Vars *v,USHORT type) {
- UBYTE *hdr = v->Txhdr;
- short n;
- USHORT crc;
-
- #ifdef DEBUGLOG
- sprintf(v->Msgbuf,"zsbhdr: %s %lx\n",frametypes[type+FTOFFSET],v->Txpos);
- dlog(v,v->Msgbuf);
- #endif
- xsendline(v,ZPAD);
- xsendline(v,ZDLE);
- xsendline(v,ZBIN);
- zsendline(v,(UBYTE)type);
-
- crc = updcrc(type, 0);
- for (n=4; --n >= 0;) {
- zsendline(v,*hdr);
- crc = updcrc(((USHORT)(*hdr++)), crc);
- }
-
- crc = updcrc(((USHORT)0),crc);
- crc = updcrc(((USHORT)0),crc);
- zsendline(v,(UBYTE)(crc>>8));
- zsendline(v,(UBYTE)crc);
- }
-
-
- /* Send ZMODEM HEX header hdr of type type */
- void zshhdr(struct Vars *v,USHORT type) {
- UBYTE *hdr = v->Txhdr;
- short n;
- USHORT crc;
-
- #ifdef DEBUGLOG
- sprintf(v->Msgbuf,"zshhdr: %s %lx\n",frametypes[type+FTOFFSET],v->Rxbytes);
- dlog(v,v->Msgbuf);
- #endif
- sendline(v,ZPAD);
- sendline(v,ZPAD);
- sendline(v,ZDLE);
- sendline(v,ZHEX);
- zputhex(v,(UBYTE)type);
-
- crc = updcrc(type, 0);
- for (n=4; --n >= 0;) {
- zputhex(v,*hdr);
- crc = updcrc(((USHORT)(*hdr++)), crc);
- }
-
- crc = updcrc(((USHORT)0),crc);
- crc = updcrc(((USHORT)0),crc);
- zputhex(v,(UBYTE)(crc>>8));
- zputhex(v,(UBYTE)crc);
-
- /* Make it printable on remote machine */
- sendline(v,'\r'); sendline(v,'\n');
- /* Uncork the remote in case a fake XOFF has stopped data flow */
- if (type != ZFIN) sendline(v,XON);
- }
-
-
- /* Send binary array buf of length length, with ending ZDLE sequence frameend */
- void zsdata(struct Vars *v,short length,USHORT frameend) {
- UBYTE *buf, *zsdataptr, c;
- USHORT crc;
-
- #ifdef DEBUGLOG
- sprintf(v->Msgbuf,"zsdata: length=%ld end=%lx\n",(long)length,(long)frameend);
- dlog(v,v->Msgbuf);
- #endif
-
- buf = v->Pktbuf;
- zsdataptr = v->Zsdatabuf;
- crc = 0;
- for (;--length >= 0;) {
- switch (c = *buf) {
- case CR:
- case CR|0x80:
- if (v->Lastzsent != '@') goto sendit;
- /* Fallthrough */
- case ZDLE:
- case DLE:
- case XON:
- case XOFF:
- case DLE|0x80:
- case XON|0x80:
- case XOFF|0x80:
- *zsdataptr++ = ZDLE;
- c ^= 0x40;
- sendit:
- default:
- *zsdataptr++ = v->Lastzsent = c;
- }
- crc = updcrc(((USHORT)(*buf++)), crc);
- }
- *zsdataptr++ = ZDLE;
- *zsdataptr++ = frameend;
- crc = updcrc(frameend, crc);
- (*v->io.xpr_swrite)(v->Zsdatabuf,(long)(zsdataptr - v->Zsdatabuf));
-
- crc = updcrc(((USHORT)0),crc);
- crc = updcrc(((USHORT)0),crc);
- zsendline(v,(UBYTE)(crc>>8));
- zsendline(v,(UBYTE)crc);
-
- if (frameend == ZCRCW) xsendline(v,XON);
- }
-
-
- /* Receive array buf of max length with ending ZDLE sequence
- and CRC. Returns the ending character or error code. */
- short zrdata(struct Vars *v,UBYTE *buf,short length) {
- short c, d;
- USHORT crc;
-
- crc = v->Rxcount = 0;
- for (;;) {
- if ((c = zdlread(v)) & ~0xFF) {
- crcfoo:
- switch (c) {
- case GOTCRCE:
- case GOTCRCG:
- case GOTCRCQ:
- case GOTCRCW:
- crc = updcrc(((d=c)&0xFF), crc);
- if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
- crc = updcrc(c, crc);
- if ((c = zdlread(v)) & ~0xFF) goto crcfoo;
- crc = updcrc(c, crc);
- if (crc & 0xFFFF) {
- strcpy(v->Msgbuf,"Bad data packet CRC ");
- return ERROR;
- }
- #ifdef DEBUGLOG
- sprintf(v->Msgbuf,"zrdata: cnt = %ld ret = %lx\n",(long)v->Rxcount,(long)d);
- dlog(v,v->Msgbuf);
- #endif
- return d;
- case GOTCAN:
- return ZCAN;
- case TIMEOUT:
- strcpy(v->Msgbuf,"Data packet timeout ");
- return c;
- case RCDO:
- return c;
- default:
- strcpy(v->Msgbuf,"Unrecognizable data packet ");
- return c;
- }
- }
- if (--length < 0) {
- strcpy(v->Msgbuf,"Data packet too long ");
- return ERROR;
- }
- ++v->Rxcount;
- *buf++ = c;
- crc = updcrc(c, crc);
- continue;
- }
- }
-
-
- /* Read a ZMODEM header to hdr, either binary or hex.
- On success return type of header.
- Otherwise return negative on error. */
- short zgethdr(struct Vars *v) {
- short c, cancount;
- long n;
- #ifdef DEBUGLOG
- UBYTE msgbuf[128];
- #endif
-
- n = v->Baud; /* Max characters before start of frame */
- cancount = 5;
- again:
- v->Rxframeind = v->Rxtype = 0;
- switch (c = noxrd7(v)) {
- case RCDO:
- case TIMEOUT:
- goto fifi;
- case CAN:
- if (--cancount <= 0) {
- c = ZCAN;
- goto fifi;
- }
- default:
- agn2:
- if (--n <= 0) {
- strcpy(v->Msgbuf,"Header search garbage count exceeded ");
- return ERROR;
- }
- if (c != CAN) cancount = 5;
- goto again;
- case ZPAD: /* This is what we want. */
- break;
- }
- cancount = 5;
- splat:
- switch (c = noxrd7(v)) {
- case ZPAD:
- goto splat;
- case RCDO:
- case TIMEOUT:
- goto fifi;
- default:
- goto agn2;
- case ZDLE: /* This is what we want. */
- break;
- }
-
- switch (c = noxrd7(v)) {
- case RCDO:
- case TIMEOUT:
- goto fifi;
- case ZBIN:
- v->Rxframeind = ZBIN;
- c = zrbhdr(v);
- break;
- case ZHEX:
- v->Rxframeind = ZHEX;
- c = zrhhdr(v);
- break;
- case CAN:
- if (--cancount <= 0) {
- c = ZCAN;
- goto fifi;
- }
- goto agn2;
- default:
- goto agn2;
- }
- v->Rxpos = rclhdr(v);
- fifi:
- switch (c) {
- case GOTCAN:
- c = ZCAN;
- case ZNAK:
- case ZCAN:
- case ERROR:
- case TIMEOUT:
- case RCDO:
- sprintf(v->Msgbuf,"%s %s ", frametypes[c+FTOFFSET],
- (c >= 0) ? "header" : "error");
- #ifdef DEBUGLOG
- default:
- if (c >= -3 && c <= FRTYPES)
- sprintf(msgbuf,"zgethdr: %s @ %ld\n",frametypes[c+FTOFFSET],v->Rxpos);
- else
- sprintf(msgbuf,"zgethdr: Unknown type %ld @ %ld\n",(long)c,v->Rxpos);
- dlog(v,msgbuf);
- #endif
- }
- return c;
- }
-
-
- /* Receive a binary style header (type and position) */
- short zrbhdr(struct Vars *v) {
- UBYTE *hdr = v->Rxhdr;
- short c, n;
- USHORT crc;
-
- if ((c = zdlread(v)) & ~0xFF) return c;
- v->Rxtype = c;
- crc = updcrc(c, 0);
-
- for (n=4; --n >= 0;) {
- if ((c = zdlread(v)) & ~0xFF) return c;
- crc = updcrc(c, crc);
- *hdr++ = c;
- }
- if ((c = zdlread(v)) & ~0xFF) return c;
- crc = updcrc(c, crc);
- if ((c = zdlread(v)) & ~0xFF) return c;
- crc = updcrc(c, crc);
- if (crc & 0xFFFF) {
- strcpy(v->Msgbuf,"Bad Header CRC ");
- return ERROR;
- }
- return v->Rxtype;
- }
-
-
- /* Receive a hex style header (type and position) */
- short zrhhdr(struct Vars *v) {
- UBYTE *hdr = v->Rxhdr;
- short c, n;
- USHORT crc;
-
- if ((c = zgethex(v)) < 0) return c;
- v->Rxtype = c;
- crc = updcrc(c, 0);
-
- for (n=4; --n >= 0;) {
- if ((c = zgethex(v)) < 0) return c;
- crc = updcrc(c, crc);
- *hdr++ = c;
- }
- if ((c = zgethex(v)) < 0) return c;
- crc = updcrc(c, crc);
- if ((c = zgethex(v)) < 0) return c;
- crc = updcrc(c, crc);
- if (crc & 0xFFFF) {
- strcpy(v->Msgbuf,"Bad Header CRC ");
- return ERROR;
- }
- if (readock(v,1) == '\r') readock(v,1); /* Throw away possible cr/lf */
- return v->Rxtype;
- }
-
-
- /* Send a byte as two hex digits */
- void zputhex(struct Vars *v,UBYTE c) {
- static char digits[] = "0123456789abcdef";
-
- sendline(v,digits[(c>>4) & 0x0F]);
- sendline(v,digits[c & 0x0F]);
- }
-
-
- /* Send character c with ZMODEM escape sequence encoding.
- Escape ZDLE, real DLE, XON, XOFF, and CR following @ (Telenet net escape) */
- void zsendline(struct Vars *v,UBYTE c) {
- switch (c) {
- case CR:
- case CR|0x80:
- if (v->Lastzsent != '@') goto sendit;
- /* Fallthrough */
- case ZDLE:
- case DLE:
- case XON:
- case XOFF:
- case DLE|0x80:
- case XON|0x80:
- case XOFF|0x80:
- xsendline(v,ZDLE);
- c ^= 0x40;
- sendit:
- default:
- xsendline(v,v->Lastzsent = c);
- }
- }
-
-
- /* Decode two lower case hex digits into an 8 bit byte value */
- short zgethex(struct Vars *v) {
- short c, n;
-
- if ((n = noxrd7(v)) < 0) return n;
- n -= '0';
- if (n > 9) n -= ('a' - ':');
- if (n & ~0xF) return ERROR;
-
- if ((c = noxrd7(v)) < 0) return c;
- c -= '0';
- if (c > 9) c -= ('a' - ':');
- if (c & ~0xF) return ERROR;
-
- return (short)(n<<4 | c);
- }
-
-
- /* Read a byte, checking for ZMODEM escape encoding
- including CAN*5 which represents a quick abort */
- short zdlread(struct Vars *v) {
- short c;
-
- if ((c = readock(v,v->Rxtimeout)) != ZDLE) return c;
- if ((c = readock(v,v->Rxtimeout)) < 0) return c;
- if (c == CAN && (c = readock(v,v->Rxtimeout)) < 0) return c;
- if (c == CAN && (c = readock(v,v->Rxtimeout)) < 0) return c;
- if (c == CAN && (c = readock(v,v->Rxtimeout)) < 0) return c;
- switch (c) {
- case CAN:
- return GOTCAN;
- case ZCRCE:
- case ZCRCG:
- case ZCRCQ:
- case ZCRCW:
- return (short)(c | GOTOR);
- case ZRUB0:
- return 0x7F;
- case ZRUB1:
- return 0xFF;
- default:
- if ((c & 0x60) == 0x40) return (short)(c ^ 0x40);
- break;
- }
- strcpy(v->Msgbuf,"Bad ZMODEM escape sequence ");
- return ERROR;
- }
-
-
- /* Read a character from the modem line with timeout.
- Eat parity, XON and XOFF characters. */
- short noxrd7(struct Vars *v) {
- short c;
-
- for (;;) {
- if ((c = readock(v,v->Rxtimeout)) < 0) return c;
- switch (c &= 0x7F) {
- case XON:
- case XOFF:
- continue;
- default:
- return c;
- }
- }
- }
-
-
- /* Store long integer pos in Txhdr */
- void stohdr(struct Vars *v,long pos) {
- v->Txhdr[ZP0] = pos;
- pos >>= 8;
- v->Txhdr[ZP1] = pos;
- pos >>= 8;
- v->Txhdr[ZP2] = pos;
- pos >>= 8;
- v->Txhdr[ZP3] = pos;
- }
-
-
- /* Recover a long integer from a header */
- long rclhdr(struct Vars *v) {
- long l;
-
- l = v->Rxhdr[ZP3];
- l = (l << 8) | v->Rxhdr[ZP2];
- l = (l << 8) | v->Rxhdr[ZP1];
- l = (l << 8) | v->Rxhdr[ZP0];
- return l;
- }
-