790 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			790 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *   Z M . C
 | 
						|
 *    ZMODEM protocol primitives
 | 
						|
 *    05-09-88  Chuck Forsberg Omen Technology Inc
 | 
						|
 *
 | 
						|
 * Entry point Functions:
 | 
						|
 *	zsbhdr(type, hdr) send binary header
 | 
						|
 *	zshhdr(type, hdr) send hex header
 | 
						|
 *	zgethdr(hdr, eflag) receive header - binary or hex
 | 
						|
 *	zsdata(buf, len, frameend) send data
 | 
						|
 *	zrdata(buf, len) receive data
 | 
						|
 *	stohdr(pos) store position data in Txhdr
 | 
						|
 *	long rclhdr(hdr) recover position offset from header
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef CANFDX
 | 
						|
#include "zmodem.h"
 | 
						|
#endif
 | 
						|
int Rxtimeout = 100;		/* Tenths of seconds to wait for something */
 | 
						|
 | 
						|
#ifndef UNSL
 | 
						|
#define UNSL
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* Globals used by ZMODEM functions */
 | 
						|
int Rxframeind;		/* ZBIN ZBIN32, or ZHEX type of frame received */
 | 
						|
int Rxtype;		/* Type of header received */
 | 
						|
int Rxcount;		/* Count of data bytes received */
 | 
						|
char Rxhdr[4];		/* Received header */
 | 
						|
char Txhdr[4];		/* Transmitted header */
 | 
						|
long Rxpos;		/* Received file position */
 | 
						|
long Txpos;		/* Transmitted file position */
 | 
						|
int Txfcs32;		/* TURE means send binary frames with 32 bit FCS */
 | 
						|
int Crc32t;		/* Display flag indicating 32 bit CRC being sent */
 | 
						|
int Crc32;		/* Display flag indicating 32 bit CRC being received */
 | 
						|
int Znulls;		/* Number of nulls to send at beginning of ZDATA hdr */
 | 
						|
char Attn[ZATTNLEN+1];	/* Attention string rx sends to tx on err */
 | 
						|
 | 
						|
static lastsent;	/* Last char we sent */
 | 
						|
static Not8bit;		/* Seven bits seen on header */
 | 
						|
 | 
						|
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 */
 | 
						|
};
 | 
						|
 | 
						|
static char badcrc[] = "Bad CRC";
 | 
						|
 | 
						|
/* Send ZMODEM binary header hdr of type type */
 | 
						|
void zsbhdr(type, hdr)
 | 
						|
int type;
 | 
						|
register char *hdr;
 | 
						|
{
 | 
						|
	register int n;
 | 
						|
	register unsigned short crc;
 | 
						|
 | 
						|
	vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
 | 
						|
	if (type == ZDATA)
 | 
						|
		for (n = Znulls; --n >=0; )
 | 
						|
			xsendline(0);
 | 
						|
 | 
						|
	xsendline(ZPAD); xsendline(ZDLE);
 | 
						|
 | 
						|
	if (Crc32t=Txfcs32)
 | 
						|
		zsbh32(hdr, type);
 | 
						|
	else {
 | 
						|
		xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
 | 
						|
 | 
						|
		for (n=4; --n >= 0; ++hdr) {
 | 
						|
			zsendline(*hdr);
 | 
						|
			crc = updcrc((0377& *hdr), crc);
 | 
						|
		}
 | 
						|
		crc = updcrc(0,updcrc(0,crc));
 | 
						|
		zsendline(crc>>8);
 | 
						|
		zsendline(crc);
 | 
						|
	}
 | 
						|
	if (type != ZDATA)
 | 
						|
		flushmo();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Send ZMODEM binary header hdr of type type */
 | 
						|
void zsbh32(hdr, type)
 | 
						|
register char *hdr;
 | 
						|
int type;
 | 
						|
{
 | 
						|
	register int n;
 | 
						|
	register UNSL long crc;
 | 
						|
 | 
						|
	xsendline(ZBIN32);  zsendline(type);
 | 
						|
	crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
 | 
						|
 | 
						|
	for (n=4; --n >= 0; ++hdr) {
 | 
						|
		crc = UPDC32((0377 & *hdr), crc);
 | 
						|
		zsendline(*hdr);
 | 
						|
	}
 | 
						|
	crc = ~crc;
 | 
						|
	for (n=4; --n >= 0;) {
 | 
						|
		zsendline((int)crc);
 | 
						|
		crc >>= 8;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Send ZMODEM HEX header hdr of type type */
 | 
						|
void zshhdr(type, hdr)
 | 
						|
int type;
 | 
						|
register char *hdr;
 | 
						|
{
 | 
						|
	register int n;
 | 
						|
	register unsigned short crc;
 | 
						|
 | 
						|
	vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
 | 
						|
	sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
 | 
						|
	zputhex(type);
 | 
						|
	Crc32t = 0;
 | 
						|
 | 
						|
	crc = updcrc(type, 0);
 | 
						|
	for (n=4; --n >= 0; ++hdr) {
 | 
						|
		zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
 | 
						|
	}
 | 
						|
	crc = updcrc(0,updcrc(0,crc));
 | 
						|
	zputhex(crc>>8); zputhex(crc);
 | 
						|
 | 
						|
	/* Make it printable on remote machine */
 | 
						|
	sendline(015); sendline(0212);
 | 
						|
	/*
 | 
						|
	 * Uncork the remote in case a fake XOFF has stopped data flow
 | 
						|
	 */
 | 
						|
	if (type != ZFIN && type != ZACK)
 | 
						|
		sendline(021);
 | 
						|
	flushmo();
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Send binary array buf of length length, with ending ZDLE sequence frameend
 | 
						|
 */
 | 
						|
static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
 | 
						|
 | 
						|
void zsdata(buf, length, frameend)
 | 
						|
register char *buf;
 | 
						|
int length;
 | 
						|
int frameend;
 | 
						|
{
 | 
						|
	register unsigned short crc;
 | 
						|
 | 
						|
	vfile("zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]);
 | 
						|
	if (Crc32t)
 | 
						|
		zsda32(buf, length, frameend);
 | 
						|
	else {
 | 
						|
		crc = 0;
 | 
						|
		for (;--length >= 0; ++buf) {
 | 
						|
			zsendline(*buf); crc = updcrc((0377 & *buf), crc);
 | 
						|
		}
 | 
						|
		xsendline(ZDLE); xsendline(frameend);
 | 
						|
		crc = updcrc(frameend, crc);
 | 
						|
 | 
						|
		crc = updcrc(0,updcrc(0,crc));
 | 
						|
		zsendline(crc>>8); zsendline(crc);
 | 
						|
	}
 | 
						|
	if (frameend == ZCRCW) {
 | 
						|
		xsendline(XON);  flushmo();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void zsda32(buf, length, frameend)
 | 
						|
register char *buf;
 | 
						|
int length;
 | 
						|
int frameend;
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
	register UNSL long crc;
 | 
						|
 | 
						|
	crc = 0xFFFFFFFFL;
 | 
						|
	for (;--length >= 0; ++buf) {
 | 
						|
		c = *buf & 0377;
 | 
						|
		if (c & 0140)
 | 
						|
			xsendline(lastsent = c);
 | 
						|
		else
 | 
						|
			zsendline(c);
 | 
						|
		crc = UPDC32(c, crc);
 | 
						|
	}
 | 
						|
	xsendline(ZDLE); xsendline(frameend);
 | 
						|
	crc = UPDC32(frameend, crc);
 | 
						|
 | 
						|
	crc = ~crc;
 | 
						|
	for (length=4; --length >= 0;) {
 | 
						|
		zsendline((int)crc);  crc >>= 8;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Receive array buf of max length with ending ZDLE sequence
 | 
						|
 *  and CRC.  Returns the ending character or error code.
 | 
						|
 *  NB: On errors may store length+1 bytes!
 | 
						|
 */
 | 
						|
int zrdata(buf, length)
 | 
						|
register char *buf;
 | 
						|
int length;
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
	register unsigned short crc;
 | 
						|
	register char *end;
 | 
						|
	register int d;
 | 
						|
 | 
						|
	if (Rxframeind == ZBIN32)
 | 
						|
		return zrdat32(buf, length);
 | 
						|
 | 
						|
	crc = Rxcount = 0;  end = buf + length;
 | 
						|
	while (buf <= end) {
 | 
						|
		if ((c = zdlread()) & ~0377) {
 | 
						|
crcfoo:
 | 
						|
			switch (c) {
 | 
						|
			case GOTCRCE:
 | 
						|
			case GOTCRCG:
 | 
						|
			case GOTCRCQ:
 | 
						|
			case GOTCRCW:
 | 
						|
				crc = updcrc((d=c)&0377, crc);
 | 
						|
				if ((c = zdlread()) & ~0377)
 | 
						|
					goto crcfoo;
 | 
						|
				crc = updcrc(c, crc);
 | 
						|
				if ((c = zdlread()) & ~0377)
 | 
						|
					goto crcfoo;
 | 
						|
				crc = updcrc(c, crc);
 | 
						|
				if (crc & 0xFFFF) {
 | 
						|
					zperr(badcrc);
 | 
						|
					return ERROR;
 | 
						|
				}
 | 
						|
				Rxcount = length - (end - buf);
 | 
						|
				vfile("zrdata: %d  %s", Rxcount,
 | 
						|
				 Zendnames[(d-GOTCRCE)&3]);
 | 
						|
				return d;
 | 
						|
			case GOTCAN:
 | 
						|
				zperr("Sender Canceled");
 | 
						|
				return ZCAN;
 | 
						|
			case TIMEOUT:
 | 
						|
				zperr("TIMEOUT");
 | 
						|
				return c;
 | 
						|
			default:
 | 
						|
				zperr("Bad data subpacket");
 | 
						|
				return c;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		*buf++ = c;
 | 
						|
		crc = updcrc(c, crc);
 | 
						|
	}
 | 
						|
	zperr("Data subpacket too long");
 | 
						|
	return ERROR;
 | 
						|
}
 | 
						|
 | 
						|
int zrdat32(buf, length)
 | 
						|
register char *buf;
 | 
						|
int length;
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
	register UNSL long crc;
 | 
						|
	register char *end;
 | 
						|
	register int d;
 | 
						|
 | 
						|
	crc = 0xFFFFFFFFL;  Rxcount = 0;  end = buf + length;
 | 
						|
	while (buf <= end) {
 | 
						|
		if ((c = zdlread()) & ~0377) {
 | 
						|
crcfoo:
 | 
						|
			switch (c) {
 | 
						|
			case GOTCRCE:
 | 
						|
			case GOTCRCG:
 | 
						|
			case GOTCRCQ:
 | 
						|
			case GOTCRCW:
 | 
						|
				d = c;  c &= 0377;
 | 
						|
				crc = UPDC32(c, crc);
 | 
						|
				if ((c = zdlread()) & ~0377)
 | 
						|
					goto crcfoo;
 | 
						|
				crc = UPDC32(c, crc);
 | 
						|
				if ((c = zdlread()) & ~0377)
 | 
						|
					goto crcfoo;
 | 
						|
				crc = UPDC32(c, crc);
 | 
						|
				if ((c = zdlread()) & ~0377)
 | 
						|
					goto crcfoo;
 | 
						|
				crc = UPDC32(c, crc);
 | 
						|
				if ((c = zdlread()) & ~0377)
 | 
						|
					goto crcfoo;
 | 
						|
				crc = UPDC32(c, crc);
 | 
						|
				if (crc != 0xDEBB20E3) {
 | 
						|
					zperr(badcrc);
 | 
						|
					return ERROR;
 | 
						|
				}
 | 
						|
				Rxcount = length - (end - buf);
 | 
						|
				vfile("zrdat32: %d %s", Rxcount,
 | 
						|
				 Zendnames[(d-GOTCRCE)&3]);
 | 
						|
				return d;
 | 
						|
			case GOTCAN:
 | 
						|
				zperr("Sender Canceled");
 | 
						|
				return ZCAN;
 | 
						|
			case TIMEOUT:
 | 
						|
				zperr("TIMEOUT");
 | 
						|
				return c;
 | 
						|
			default:
 | 
						|
				zperr("Bad data subpacket");
 | 
						|
				return c;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		*buf++ = c;
 | 
						|
		crc = UPDC32(c, crc);
 | 
						|
	}
 | 
						|
	zperr("Data subpacket too long");
 | 
						|
	return ERROR;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Read a ZMODEM header to hdr, either binary or hex.
 | 
						|
 *  eflag controls local display of non zmodem characters:
 | 
						|
 *	0:  no display
 | 
						|
 *	1:  display printing characters only
 | 
						|
 *	2:  display all non ZMODEM characters
 | 
						|
 *  On success, set Zmodem to 1, set Rxpos and return type of header.
 | 
						|
 *   Otherwise return negative on error.
 | 
						|
 *   Return ERROR instantly if ZCRCW sequence, for fast error recovery.
 | 
						|
 */
 | 
						|
int zgethdr(hdr, eflag)
 | 
						|
char *hdr;
 | 
						|
int eflag;
 | 
						|
{
 | 
						|
	register int c, n, cancount;
 | 
						|
 | 
						|
	n = Zrwindow + Baudrate;	/* Max bytes before start of frame */
 | 
						|
	Rxframeind = Rxtype = 0;
 | 
						|
 | 
						|
startover:
 | 
						|
	cancount = 5;
 | 
						|
again:
 | 
						|
	/* Return immediate ERROR if ZCRCW sequence seen */
 | 
						|
	switch (c = readline(Rxtimeout)) {
 | 
						|
	case RCDO:
 | 
						|
	case TIMEOUT:
 | 
						|
		goto fifi;
 | 
						|
	case CAN:
 | 
						|
gotcan:
 | 
						|
		if (--cancount <= 0) {
 | 
						|
			c = ZCAN; goto fifi;
 | 
						|
		}
 | 
						|
		switch (c = readline(1)) {
 | 
						|
		case TIMEOUT:
 | 
						|
			goto again;
 | 
						|
		case ZCRCW:
 | 
						|
			c = ERROR;
 | 
						|
		/* **** FALL THRU TO **** */
 | 
						|
		case RCDO:
 | 
						|
			goto fifi;
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
		case CAN:
 | 
						|
			if (--cancount <= 0) {
 | 
						|
				c = ZCAN; goto fifi;
 | 
						|
			}
 | 
						|
			goto again;
 | 
						|
		}
 | 
						|
	/* **** FALL THRU TO **** */
 | 
						|
	default:
 | 
						|
agn2:
 | 
						|
		if ( --n == 0) {
 | 
						|
			zperr("Garbage count exceeded");
 | 
						|
			return(ERROR);
 | 
						|
		}
 | 
						|
		if (eflag && ((c &= 0177) & 0140))
 | 
						|
			bttyout(c);
 | 
						|
		else if (eflag > 1)
 | 
						|
			bttyout(c);
 | 
						|
#ifdef UNIX
 | 
						|
		fflush(stderr);
 | 
						|
#endif
 | 
						|
		goto startover;
 | 
						|
	case ZPAD|0200:		/* This is what we want. */
 | 
						|
		Not8bit = c;
 | 
						|
	case ZPAD:		/* This is what we want. */
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	cancount = 5;
 | 
						|
splat:
 | 
						|
	switch (c = noxrd7()) {
 | 
						|
	case ZPAD:
 | 
						|
		goto splat;
 | 
						|
	case RCDO:
 | 
						|
	case TIMEOUT:
 | 
						|
		goto fifi;
 | 
						|
	default:
 | 
						|
		goto agn2;
 | 
						|
	case ZDLE:		/* This is what we want. */
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (c = noxrd7()) {
 | 
						|
	case RCDO:
 | 
						|
	case TIMEOUT:
 | 
						|
		goto fifi;
 | 
						|
	case ZBIN:
 | 
						|
		Rxframeind = ZBIN;  Crc32 = FALSE;
 | 
						|
		c =  zrbhdr(hdr);
 | 
						|
		break;
 | 
						|
	case ZBIN32:
 | 
						|
		Crc32 = Rxframeind = ZBIN32;
 | 
						|
		c =  zrbhdr32(hdr);
 | 
						|
		break;
 | 
						|
	case ZHEX:
 | 
						|
		Rxframeind = ZHEX;  Crc32 = FALSE;
 | 
						|
		c =  zrhhdr(hdr);
 | 
						|
		break;
 | 
						|
	case CAN:
 | 
						|
		goto gotcan;
 | 
						|
	default:
 | 
						|
		goto agn2;
 | 
						|
	}
 | 
						|
	Rxpos = hdr[ZP3] & 0377;
 | 
						|
	Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
 | 
						|
	Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
 | 
						|
	Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
 | 
						|
fifi:
 | 
						|
	switch (c) {
 | 
						|
	case GOTCAN:
 | 
						|
		c = ZCAN;
 | 
						|
	/* **** FALL THRU TO **** */
 | 
						|
	case ZNAK:
 | 
						|
	case ZCAN:
 | 
						|
	case ERROR:
 | 
						|
	case TIMEOUT:
 | 
						|
	case RCDO:
 | 
						|
		zperr("Got %s", frametypes[c+FTOFFSET]);
 | 
						|
	/* **** FALL THRU TO **** */
 | 
						|
	default:
 | 
						|
		if (c >= -3 && c <= FRTYPES)
 | 
						|
			vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
 | 
						|
		else
 | 
						|
			vfile("zgethdr: %d %lx", c, Rxpos);
 | 
						|
	}
 | 
						|
	return c;
 | 
						|
}
 | 
						|
 | 
						|
/* Receive a binary style header (type and position) */
 | 
						|
int zrbhdr(hdr)
 | 
						|
register char *hdr;
 | 
						|
{
 | 
						|
	register int c, n;
 | 
						|
	register unsigned short crc;
 | 
						|
 | 
						|
	if ((c = zdlread()) & ~0377)
 | 
						|
		return c;
 | 
						|
	Rxtype = c;
 | 
						|
	crc = updcrc(c, 0);
 | 
						|
 | 
						|
	for (n=4; --n >= 0; ++hdr) {
 | 
						|
		if ((c = zdlread()) & ~0377)
 | 
						|
			return c;
 | 
						|
		crc = updcrc(c, crc);
 | 
						|
		*hdr = c;
 | 
						|
	}
 | 
						|
	if ((c = zdlread()) & ~0377)
 | 
						|
		return c;
 | 
						|
	crc = updcrc(c, crc);
 | 
						|
	if ((c = zdlread()) & ~0377)
 | 
						|
		return c;
 | 
						|
	crc = updcrc(c, crc);
 | 
						|
	if (crc & 0xFFFF) {
 | 
						|
		zperr(badcrc);
 | 
						|
		return ERROR;
 | 
						|
	}
 | 
						|
#ifdef ZMODEM
 | 
						|
	Protocol = ZMODEM;
 | 
						|
#endif
 | 
						|
	Zmodem = 1;
 | 
						|
	return Rxtype;
 | 
						|
}
 | 
						|
 | 
						|
/* Receive a binary style header (type and position) with 32 bit FCS */
 | 
						|
int zrbhdr32(hdr)
 | 
						|
register char *hdr;
 | 
						|
{
 | 
						|
	register int c, n;
 | 
						|
	register UNSL long crc;
 | 
						|
 | 
						|
	if ((c = zdlread()) & ~0377)
 | 
						|
		return c;
 | 
						|
	Rxtype = c;
 | 
						|
	crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
 | 
						|
#ifdef DEBUGZ
 | 
						|
	vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
 | 
						|
#endif
 | 
						|
 | 
						|
	for (n=4; --n >= 0; ++hdr) {
 | 
						|
		if ((c = zdlread()) & ~0377)
 | 
						|
			return c;
 | 
						|
		crc = UPDC32(c, crc);
 | 
						|
		*hdr = c;
 | 
						|
#ifdef DEBUGZ
 | 
						|
		vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	for (n=4; --n >= 0;) {
 | 
						|
		if ((c = zdlread()) & ~0377)
 | 
						|
			return c;
 | 
						|
		crc = UPDC32(c, crc);
 | 
						|
#ifdef DEBUGZ
 | 
						|
		vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (crc != 0xDEBB20E3) {
 | 
						|
		zperr(badcrc);
 | 
						|
		return ERROR;
 | 
						|
	}
 | 
						|
#ifdef ZMODEM
 | 
						|
	Protocol = ZMODEM;
 | 
						|
#endif
 | 
						|
	Zmodem = 1;
 | 
						|
	return Rxtype;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Receive a hex style header (type and position) */
 | 
						|
int zrhhdr(hdr)
 | 
						|
char *hdr;
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
	register unsigned short crc;
 | 
						|
	register int n;
 | 
						|
 | 
						|
	if ((c = zgethex()) < 0)
 | 
						|
		return c;
 | 
						|
	Rxtype = c;
 | 
						|
	crc = updcrc(c, 0);
 | 
						|
 | 
						|
	for (n=4; --n >= 0; ++hdr) {
 | 
						|
		if ((c = zgethex()) < 0)
 | 
						|
			return c;
 | 
						|
		crc = updcrc(c, crc);
 | 
						|
		*hdr = c;
 | 
						|
	}
 | 
						|
	if ((c = zgethex()) < 0)
 | 
						|
		return c;
 | 
						|
	crc = updcrc(c, crc);
 | 
						|
	if ((c = zgethex()) < 0)
 | 
						|
		return c;
 | 
						|
	crc = updcrc(c, crc);
 | 
						|
	if (crc & 0xFFFF) {
 | 
						|
		zperr(badcrc); return ERROR;
 | 
						|
	}
 | 
						|
	switch ( c = readline(1)) {
 | 
						|
	case 0215:
 | 
						|
		Not8bit = c;
 | 
						|
		/* **** FALL THRU TO **** */
 | 
						|
	case 015:
 | 
						|
	 	/* Throw away possible cr/lf */
 | 
						|
		switch (c = readline(1)) {
 | 
						|
		case 012:
 | 
						|
			Not8bit |= c;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#ifdef ZMODEM
 | 
						|
	Protocol = ZMODEM;
 | 
						|
#endif
 | 
						|
	Zmodem = 1; return Rxtype;
 | 
						|
}
 | 
						|
 | 
						|
/* Send a byte as two hex digits */
 | 
						|
void zputhex(c)
 | 
						|
register int c;
 | 
						|
{
 | 
						|
	static char	digits[]	= "0123456789abcdef";
 | 
						|
 | 
						|
	if (Verbose>8)
 | 
						|
		vfile("zputhex: %02X", c);
 | 
						|
	sendline(digits[(c&0xF0)>>4]);
 | 
						|
	sendline(digits[(c)&0xF]);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Send character c with ZMODEM escape sequence encoding.
 | 
						|
 *  Escape XON, XOFF. Escape CR following @ (Telenet net escape)
 | 
						|
 */
 | 
						|
void zsendline(c)
 | 
						|
int c;
 | 
						|
{
 | 
						|
 | 
						|
	/* Quick check for non control characters */
 | 
						|
	if (c & 0140)
 | 
						|
		xsendline(lastsent = c);
 | 
						|
	else {
 | 
						|
		switch (c &= 0377) {
 | 
						|
		case ZDLE:
 | 
						|
			xsendline(ZDLE);
 | 
						|
			xsendline (lastsent = (c ^= 0100));
 | 
						|
			break;
 | 
						|
		case 015:
 | 
						|
		case 0215:
 | 
						|
			if (!Zctlesc && (lastsent & 0177) != '@')
 | 
						|
				goto sendit;
 | 
						|
		/* **** FALL THRU TO **** */
 | 
						|
		case 020:
 | 
						|
		case 021:
 | 
						|
		case 023:
 | 
						|
		case 0220:
 | 
						|
		case 0221:
 | 
						|
		case 0223:
 | 
						|
			xsendline(ZDLE);
 | 
						|
			c ^= 0100;
 | 
						|
	sendit:
 | 
						|
			xsendline(lastsent = c);
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			if (Zctlesc && ! (c & 0140)) {
 | 
						|
				xsendline(ZDLE);
 | 
						|
				c ^= 0100;
 | 
						|
			}
 | 
						|
			xsendline(lastsent = c);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Decode two lower case hex digits into an 8 bit byte value */
 | 
						|
int zgethex()
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
 | 
						|
	c = zgeth1();
 | 
						|
	if (Verbose>8)
 | 
						|
		vfile("zgethex: %02X", c);
 | 
						|
	return c;
 | 
						|
}
 | 
						|
int zgeth1()
 | 
						|
{
 | 
						|
	register int c, n;
 | 
						|
 | 
						|
	if ((c = noxrd7()) < 0)
 | 
						|
		return c;
 | 
						|
	n = c - '0';
 | 
						|
	if (n > 9)
 | 
						|
		n -= ('a' - ':');
 | 
						|
	if (n & ~0xF)
 | 
						|
		return ERROR;
 | 
						|
	if ((c = noxrd7()) < 0)
 | 
						|
		return c;
 | 
						|
	c -= '0';
 | 
						|
	if (c > 9)
 | 
						|
		c -= ('a' - ':');
 | 
						|
	if (c & ~0xF)
 | 
						|
		return ERROR;
 | 
						|
	c += (n<<4);
 | 
						|
	return c;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Read a byte, checking for ZMODEM escape encoding
 | 
						|
 *  including CAN*5 which represents a quick abort
 | 
						|
 */
 | 
						|
int zdlread()
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
 | 
						|
again:
 | 
						|
	/* Quick check for non control characters */
 | 
						|
	if ((c = readline(Rxtimeout)) & 0140)
 | 
						|
		return c;
 | 
						|
	switch (c) {
 | 
						|
	case ZDLE:
 | 
						|
		break;
 | 
						|
	case 023:
 | 
						|
	case 0223:
 | 
						|
	case 021:
 | 
						|
	case 0221:
 | 
						|
		goto again;
 | 
						|
	default:
 | 
						|
		if (Zctlesc && !(c & 0140)) {
 | 
						|
			goto again;
 | 
						|
		}
 | 
						|
		return c;
 | 
						|
	}
 | 
						|
again2:
 | 
						|
	if ((c = readline(Rxtimeout)) < 0)
 | 
						|
		return c;
 | 
						|
	if (c == CAN && (c = readline(Rxtimeout)) < 0)
 | 
						|
		return c;
 | 
						|
	if (c == CAN && (c = readline(Rxtimeout)) < 0)
 | 
						|
		return c;
 | 
						|
	if (c == CAN && (c = readline(Rxtimeout)) < 0)
 | 
						|
		return c;
 | 
						|
	switch (c) {
 | 
						|
	case CAN:
 | 
						|
		return GOTCAN;
 | 
						|
	case ZCRCE:
 | 
						|
	case ZCRCG:
 | 
						|
	case ZCRCQ:
 | 
						|
	case ZCRCW:
 | 
						|
		return (c | GOTOR);
 | 
						|
	case ZRUB0:
 | 
						|
		return 0177;
 | 
						|
	case ZRUB1:
 | 
						|
		return 0377;
 | 
						|
	case 023:
 | 
						|
	case 0223:
 | 
						|
	case 021:
 | 
						|
	case 0221:
 | 
						|
		goto again2;
 | 
						|
	default:
 | 
						|
		if (Zctlesc && ! (c & 0140)) {
 | 
						|
			goto again2;
 | 
						|
		}
 | 
						|
		if ((c & 0140) ==  0100)
 | 
						|
			return (c ^ 0100);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (Verbose>1)
 | 
						|
		zperr("Bad escape sequence %x", c);
 | 
						|
	return ERROR;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Read a character from the modem line with timeout.
 | 
						|
 *  Eat parity, XON and XOFF characters.
 | 
						|
 */
 | 
						|
int noxrd7()
 | 
						|
{
 | 
						|
	register int c;
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		if ((c = readline(Rxtimeout)) < 0)
 | 
						|
			return c;
 | 
						|
		switch (c &= 0177) {
 | 
						|
		case XON:
 | 
						|
		case XOFF:
 | 
						|
			continue;
 | 
						|
		default:
 | 
						|
			if (Zctlesc && !(c & 0140))
 | 
						|
				continue;
 | 
						|
		case '\r':
 | 
						|
		case '\n':
 | 
						|
		case ZDLE:
 | 
						|
			return c;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Store long integer pos in Txhdr */
 | 
						|
void stohdr(pos)
 | 
						|
long pos;
 | 
						|
{
 | 
						|
	Txhdr[ZP0] = pos;
 | 
						|
	Txhdr[ZP1] = pos>>8;
 | 
						|
	Txhdr[ZP2] = pos>>16;
 | 
						|
	Txhdr[ZP3] = pos>>24;
 | 
						|
}
 | 
						|
 | 
						|
/* Recover a long integer from a header */
 | 
						|
long
 | 
						|
rclhdr(hdr)
 | 
						|
register char *hdr;
 | 
						|
{
 | 
						|
	register long l;
 | 
						|
 | 
						|
	l = (hdr[ZP3] & 0377);
 | 
						|
	l = (l << 8) | (hdr[ZP2] & 0377);
 | 
						|
	l = (l << 8) | (hdr[ZP1] & 0377);
 | 
						|
	l = (l << 8) | (hdr[ZP0] & 0377);
 | 
						|
	return l;
 | 
						|
}
 | 
						|
 | 
						|
/* End of zm.c */
 |