home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff261.lzh
/
XprZmodem
/
zm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-31
|
11KB
|
490 lines
/*
* 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;
}