DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T z

⟦c50b91842⟧ TextFile

    Length: 12391 (0x3067)
    Types: TextFile
    Names: »zm.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/zmodem/zm.c« 

TextFile

/*
 *   Z M . C
 *    ZMODEM protocol primitives
 *    01-19-87  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"
int Rxtimeout = 100;		/* Tenths of seconds to wait for something */
#endif

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 */
zsbhdr(type, hdr)
register char *hdr;
{
	register n;
	register unsigned short crc;

	vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
	if (type == ZDATA)
		for (n = Znulls; --n >=0; )
			zsendline(0);

	xsendline(ZPAD); xsendline(ZDLE);

	if (Txfcs32)
		zsbh32(hdr, type);
	else {
		xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);

		for (n=4; --n >= 0;) {
			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 */
zsbh32(hdr, type)
register char *hdr;
{
	register n;
	register unsigned long crc;

	xsendline(ZBIN32);  zsendline(type);
	crc = 0xFFFFFFFF; crc = UPDC32(type, crc);

	for (n=4; --n >= 0;) {
		zsendline(*hdr);
		crc = UPDC32((0377& *hdr++), crc);
	}
	crc = ~crc;
	for (n=4; --n >= 0;) {
		zsendline(crc);  crc >>= 8;
	}
}

/* Send ZMODEM HEX header hdr of type type */
zshhdr(type, hdr)
register char *hdr;
{
	register n;
	register unsigned short crc;

	vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
	sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
	zputhex(type);

	crc = updcrc(type, 0);
	for (n=4; --n >= 0;) {
		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(012);
	/*
	 * Uncork the remote in case a fake XOFF has stopped data flow
	 */
	if (type != ZFIN)
		sendline(021);
	flushmo();
}

/*
 * Send binary array buf of length length, with ending ZDLE sequence frameend
 */
zsdata(buf, length, frameend)
register char *buf;
{
	register unsigned short crc;

	vfile("zsdata: length=%d end=%x", length, frameend);
	if (Txfcs32)
		zsda32(buf, length, frameend);
	else {
		crc = 0;
		for (;--length >= 0;) {
			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();
	}
}

zsda32(buf, length, frameend)
register char *buf;
{
	register unsigned long crc;

	crc = 0xFFFFFFFF;
	for (;--length >= 0;) {
		zsendline(*buf); crc = UPDC32((0377& *buf++), crc);
	}
	xsendline(ZDLE); xsendline(frameend);
	crc = UPDC32(frameend, crc);

	crc = ~crc;
	for (length=4; --length >= 0;) {
		zsendline(crc);  crc >>= 8;
	}
}

/*
 * Receive array buf of max length with ending ZDLE sequence
 *  and CRC.  Returns the ending character or error code.
 */
zrdata(buf, length)
register char *buf;
{
	register c;
	register unsigned short crc;
	register d;

	if (Rxframeind == ZBIN32)
		return zrdat32(buf, length);

	crc = Rxcount = 0;
	for (;;) {
		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("Bad data CRC %x", crc);
					return ERROR;
				}
				vfile("zrdata: cnt = %d ret = %x", Rxcount, d);
				return d;
			case GOTCAN:
				zperr("ZMODEM: Sender Canceled");
				return ZCAN;
			case TIMEOUT:
				zperr("ZMODEM data TIMEOUT");
				return c;
			default:
				zperr("ZMODEM bad data subpacket ret=%x", c);
				return c;
			}
		}
		if (--length < 0) {
			zperr("ZMODEM data subpacket too long");
			return ERROR;
		}
		++Rxcount;
		*buf++ = c;
		crc = updcrc(c, crc);
		continue;
	}
}
zrdat32(buf, length)
register char *buf;
{
	register c;
	register unsigned long crc;
	register d;

	crc = 0xFFFFFFFF;  Rxcount = 0;
	for (;;) {
		if ((c = zdlread()) & ~0377) {
crcfoo:
			switch (c) {
			case GOTCRCE:
			case GOTCRCG:
			case GOTCRCQ:
			case GOTCRCW:
				crc = UPDC32((d=c)&0377, 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("Bad data CRC %lX", crc);
					return ERROR;
				}
				vfile("zrdat32: cnt = %d ret = %x", Rxcount, d);
				return d;
			case GOTCAN:
				zperr("ZMODEM: Sender Canceled");
				return ZCAN;
			case TIMEOUT:
				zperr("ZMODEM data TIMEOUT");
				return c;
			default:
				zperr("ZMODEM bad data subpacket ret=%x", c);
				return c;
			}
		}
		if (--length < 0) {
			zperr("ZMODEM data subpacket too long");
			return ERROR;
		}
		++Rxcount;
		*buf++ = c;
		crc = UPDC32(c, crc);
		continue;
	}
}


/*
 * 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 and return type of header.
 *   Otherwise return negative on error
 */
zgethdr(hdr, eflag)
char *hdr;
{
	register c, n, cancount;

	n = Baudrate;	/* Max characters before start of frame */
	cancount = 5;
again:
	Rxframeind = Rxtype = 0;
	switch (c = noxrd7()) {
	case RCDO:
	case TIMEOUT:
		goto fifi;
	case CAN:
		if (--cancount <= 0) {
			c = ZCAN; goto fifi;
		}
	/* **** FALL THRU TO **** */
	default:
agn2:
		if ( --n == 0) {
			zperr("ZMODEM Garbage count exceeded");
			return(ERROR);
		}
		if (eflag && ((c &= 0177) & 0140))
			bttyout(c);
		else if (eflag > 1)
			bttyout(c);
		if (c != CAN)
			cancount = 5;
		goto again;
	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;
		c =  zrbhdr(hdr);
		break;
	case ZBIN32:
		Rxframeind = ZBIN32;
		c =  zrbhdr32(hdr);
		break;
	case ZHEX:
		Rxframeind = ZHEX;
		c =  zrhhdr(hdr);
		break;
	case CAN:
		if (--cancount <= 0) {
			c = ZCAN; goto fifi;
		}
		goto agn2;
	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("ZMODEM: Got %s %s", frametypes[c+FTOFFSET],
		  (c >= 0) ? "header" : "error");
	/* **** 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) */
zrbhdr(hdr)
register char *hdr;
{
	register c, n;
	register unsigned short crc;

	if ((c = zdlread()) & ~0377)
		return c;
	Rxtype = c;
	crc = updcrc(c, 0);

	for (n=4; --n >= 0;) {
		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("Bad Header CRC"); return ERROR;
	}
	Zmodem = 1;
	return Rxtype;
}

/* Receive a binary style header (type and position) with 32 bit FCS */
zrbhdr32(hdr)
register char *hdr;
{
	register c, n;
	register unsigned long crc;

	if ((c = zdlread()) & ~0377)
		return c;
	Rxtype = c;
	crc = 0xFFFFFFFF; crc = UPDC32(c, crc);

	for (n=4; --n >= 0;) {
		if ((c = zdlread()) & ~0377)
			return c;
		crc = UPDC32(c, crc);
		*hdr++ = c;
	}
	for (n=4; --n >= 0;) {
		if ((c = zdlread()) & ~0377)
			return c;
		crc = UPDC32(c, crc);
	}
	if (crc != 0xDEBB20E3) {
		zperr("Bad Header CRC %lX", crc); return ERROR;
	}
	Zmodem = 1;
	return Rxtype;
}


/* Receive a hex style header (type and position) */
zrhhdr(hdr)
char *hdr;
{
	register c;
	register unsigned short crc;
	register n;

	if ((c = zgethex()) < 0)
		return c;
	Rxtype = c;
	crc = updcrc(c, 0);

	for (n=4; --n >= 0;) {
		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("Bad Header CRC"); return ERROR;
	}
	if (readline(1) == '\r')	/* Throw away possible cr/lf */
		readline(1);
	Zmodem = 1; return Rxtype;
}

/* Send a byte as two hex digits */
zputhex(c)
register c;
{
	static char	digits[]	= "0123456789abcdef";

	if (Verbose>4)
		vfile("zputhex: %x", 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)
 */
zsendline(c)
register c;
{
	static lastsent;

	switch (c & 0377) {
	case ZDLE:
		xsendline(ZDLE);
		xsendline (lastsent = (c ^= 0100));
		break;
	case 015:
	case 0215:
		if ((lastsent & 0177) != '@')
			goto sendit;
	/* **** FALL THRU TO **** */
	case 020:
	case 021:
	case 023:
	case 0220:
	case 0221:
	case 0223:
#ifdef ZKER
		if (Zctlesc<0)
			goto sendit;
#endif
		xsendline(ZDLE);
		c ^= 0100;
sendit:
		xsendline(lastsent = c);
		break;
	default:
#ifdef ZKER
		if (Zctlesc>0 && ! (c & 0140)) {
			xsendline(ZDLE);
			c ^= 0100;
		}
#endif
		xsendline(lastsent = c);
	}
}

/* Decode two lower case hex digits into an 8 bit byte value */
zgethex()
{
	register c;

	c = zgeth1();
	if (Verbose>4)
		vfile("zgethex: %x", c);
	return c;
}
zgeth1()
{
	register 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
 */
zdlread()
{
	register c;

	if ((c = readline(Rxtimeout)) != ZDLE)
		return c;
	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;
	default:
		if ((c & 0140) ==  0100)
			return (c ^ 0100);
		break;
	}
	zperr("Got bad ZMODEM escape sequence %x", c);
	return ERROR;
}

/*
 * Read a character from the modem line with timeout.
 *  Eat parity, XON and XOFF characters.
 */
noxrd7()
{
	register c;

	for (;;) {
		if ((c = readline(Rxtimeout)) < 0)
			return c;
		switch (c &= 0177) {
		case XON:
		case XOFF:
			continue;
		default:
			return c;
		}
	}
}

/* Store long integer pos in Txhdr */
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;
}