/*
 *   I Z M . C
 *    ZMODEM protocol primitives
 *  Copyright 2004 2011 Omen Technology INC All Rights Reserved
 *     This is UNPUBLISHED PROPRIETARY SOURCE CODE of Omen Technology INC.
 *     The Copyright notice above does not evidence any actual or intended
 *     publication such source code.
 *
 * Entry point Functions:
 *	zsbhdr(type, hdr) send binary header
 *	zshhdr(type, hdr) send hex header
 *	zgethdr() 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 UNSL
#define UNSL
#endif
int zdlread(), noxrd7(), zrbhdr(), zrhhdr(), zgethex(), zgeth1();
int zrdat32(), zrbhdr32();

/* Globals used by ZMODEM functions */
int Rxframeind;		/* ZBIN ZBIN32, ZHEX, or ZBINR32 type of frame received */
int Rxtype;		/* Type of header received */
int Rxcount;		/* Count of data bytes received */
long bytcnt;
char Rxhdr[4];		/* Received header */
char Txhdr[8];		/* 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 */

#ifdef LDP
int Zldpactive;	/* LDP protection active */
char Zaddr8[8];	/* Array for address CRC bias */
unsigned long Zcrcpreset;	/* CRC preset from filename header */
unsigned long Zcrcinit;	/* CRC init for zrdata zsdata */
char zcpyrldp[] = "Copyright 2002 Omen Technology INC All Rights Reserved";
#endif


#ifdef ZSTAB
unsigned char zstable[256] = {
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
	0120,0121,0,0123,0,0,0,0, 0130,0,0,0,0,0,0,0,

	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,

	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
	0320,0321,0,0323,0,0,0,0, 0,0,0,0,0,0,0,0,

	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,
#ifdef NOFF
	ZRUB1
#else
	0
#endif
};
#endif


#ifdef NOCOPYTX
char *secbuf;
#ifdef BOTH
no this is not supported
#endif
#else
#ifdef KKSIZE
char secbuf[KKSIZE];
#else
char secbuf[1025];
#endif
#endif


#ifdef DIAGS
static char *frametypes[] = {
	"Carrier Lost",		/* -3 */
	"TIMEOUT",		/* -2 */
	"IZERROR",		/* -1 */
#define FTOFFSET 3
	"ZRQINIT",
	"ZRINIT",
	"ZSINIT",
	"ZACK",
	"ZFILE",
	"ZSKIP",
	"ZNAK",
	"ZABORT",
	"ZFIN",
#ifdef UNIX
	"\033[7mZRPOS\033[0m",
#else
	"ZRPOS",
#endif
	"ZDATA",
	"ZEOF",
	"ZFERR",
	"ZCRC",
	"ZCHALLENGE",
	"ZCOMPL",
	"ZCAN",
	"ZFREECNT",
	"ZCOMMAND",
	"xxxxx"
#define FRTYPES 22	/* Total number of frame types in this array */
			/*  not including psuedo negative entries */
};

static char badcrc[] = "Bad CRC";
#endif /* DIAGS */

/* Send ZMODEM binary header hdr of type type */
void
zsbh32(hdr, type)
register char *hdr;
{
	register int n;
	register UNSL long crc;

	sendline((Crc32t=Txfcs32)==2 ? ZBINR32: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 binary header hdr of type type */
void
zsbhdr(type, hdr)
register char *hdr;
{
	register int n;
	register unsigned short crc;

#ifdef DIAGS
	vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
#endif
	sendline(ZPAD); sendline(ZDLE);

	Crc32t=Txfcs32;
	if (Crc32t)
		zsbh32(hdr, type);
	else
	{
		sendline(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);
	}
}



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

#ifdef DIAGS
	vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
#endif
	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);
#ifdef FLUSH
	flushmo();
#endif
}

/*
 * Send binary array buf of length length, with ending ZDLE sequence frameend
 */
#ifdef DIAGS
static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
#endif

void
zsda32(buf, length, frameend)
#ifndef MANYREGS
register
#endif
 unsigned char *buf;
register length;
{
	register int c;
	register UNSL long crc;
#ifdef ZSTAB
	register d;
#endif
#ifdef MANYREGS
	register unsigned char *p;
	register unsigned long *pcrctab;

	pcrctab = icr3tab;
	p = buf;
#endif

	crc = 0xFFFFFFFFL;
#ifdef LDP
	if (Zldpactive) {
		stohdr(bytcnt);
		for (crc=Zcrcpreset, c=0; c<8; ++c) {
#ifndef DIAGS
			vfile("c=%d Txhdr[c]=%d crc=%lX", c, Txhdr[c], crc);
#endif
			crc = UPDC32(Txhdr[c], crc);
		}
	}
#ifndef DIAGS
	vfile("Zcrcinit=%lX", Zcrcinit);
#endif
#endif

#ifdef MANYREGS
	for (;--length >= 0;) {
		c = *p++ & 0377;
	/* UPDC32(b, c) (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) */
	crc = pcrctab[(crc ^ c) & 0xff] ^ ((crc >> 8) & 0x00FFFFFF);
#else
	for (;--length >= 0; ++buf) {
		c = *buf & 0377;
		crc = UPDC32(c, crc);
#endif
#ifdef ZSTAB
		if ((d = zstable[c])) {
			sendline(ZDLE); c = d;
		}
		sendline(c);
#else		/* ZSTAB */
#ifndef NOFF
		if (c & 0140)
			sendline(c);
		else
#endif
			zsendline(c);
#endif		/* ZSTAB */
	}
	sendline(ZDLE); sendline(frameend);
	crc = UPDC32(frameend, crc);

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

void
zsdata(buf, length, frameend)
register char *buf;
{
	register unsigned short crc;
#ifdef LDP
	register m;
#endif

#ifdef DIAGS
	vfile("zsdata: %d %s", length, Zendnames[frameend-ZCRCE&3]);
#endif
	switch (Crc32t) {
	case 1:
		zsda32(buf, length, frameend);  break;
#ifdef ADDRLE
	case 2:
		zsdar32(buf, length, frameend);  break;
#endif
	default:
		crc = 0;
#ifdef LDP
		if (Zldpactive) {
			stohdr(bytcnt);
			for (crc=0xFFFF, m=0; m<4; ++m) {
#ifdef DIAGS
				vfile("m=%d Txhdr[m]=%d crc=%X", m, Txhdr[m], crc);
#endif
				crc = updcrc(0377 & Txhdr[m], crc);
			}
		}
#endif
		for (;--length >= 0; ++buf) {
			zsendline(*buf); crc = updcrc((0377 & *buf), crc);
		}
		sendline(ZDLE); sendline(frameend);
		crc = updcrc(frameend, crc);

		crc = updcrc(0,updcrc(0,crc));
		zsendline(crc>>8); zsendline(crc);
		break;
	}
	if (frameend == ZCRCW) {
		sendline(XON);
#ifdef FLUSH
		flushmo();
#endif
	}
#ifdef FLUSH
	else if (frameend != ZCRCG)
		flushmoc();
#endif
}

/*
 * 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!
 */
zrdata(buf, length)
register char *buf;
{
	register int c;
	register unsigned short crc;
	register char *end;
	register int d;

	switch (Rxframeind) {
	case ZBIN32:
		return zrdat32(buf, length);
#ifdef ADDRLE
	case ZBINR32:
		return zrdatr32(buf, length);
#endif
	}

	crc = 0;
#ifdef LDP
	if (Zldpactive) {
		stohdr(bytcnt);
		for (crc=0xFFFF, c=0; c<4; ++c) {
#ifdef DIAGS
			vfile("c=%d Txhdr[c]=%d crc=%X", c, Txhdr[c], crc);
#endif
			crc = updcrc(0377 & Txhdr[c], crc);
		}
	}
#endif
	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) {
#ifdef DIAGS
					zbitch(badcrc);
#endif
					return IZERROR;
				}
				Rxcount = length - (end - buf);
#ifdef DIAGS
				vfile("zrdata: %d  %s", Rxcount,
				 Zendnames[d-GOTCRCE&3]);
#endif
				return d;
			case GOTCAN:
#ifdef UNIX
				zbitch("Sender Canceled");
#endif
				return ZCAN;
			case TIMEOUT:
#ifdef UNIX
				zbitch("TIMEOUT");
#endif
				return c;
			default:
#ifdef UNIX
				zbitch("Bad data subpacket");
#endif
				return c;
			}
		}
		*buf++ = c;
		crc = updcrc(c, crc);
	}
#ifdef UNIX
	zbitch("Data subpacket too long");
#endif
	return IZERROR;
}

zrdat32(buf, length)
register char *buf;
{
	register int c;
	register UNSL long crc;
	register char *end;
	register int d;

#ifdef LDP
	if (Zldpactive) {
		stohdr(bytcnt);
		for (crc=Zcrcpreset, c=0; c<8; ++c) {
#ifndef DIAGS
			vfile("c=%d Txhdr[c]=%d crc=%lX", c, Txhdr[c], crc);
#endif
			crc = UPDC32(Txhdr[c], crc);
		}
	} else
		crc = 0xFFFFFFFFL;
#ifndef DIAGS
	vfile("zrdata: bytcnt=%lX Zcrcinit=%lX", (long) bytcnt, Zcrcinit);
#endif
#else
	crc = 0xFFFFFFFFL;
#endif

	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) {
#ifdef DIAGS
					zbitch(badcrc);
#endif
					return IZERROR;
				}
				Rxcount = length - (end - buf);
#ifdef DIAGS
				vfile("zrdat32: %d %s", Rxcount,
				 Zendnames[d-GOTCRCE&3]);
#endif
				return d;
			case GOTCAN:
#ifdef UNIX
				zbitch("Sender Canceled");
#endif
				return ZCAN;
			case TIMEOUT:
#ifdef UNIX
				zbitch("TIMEOUT");
#endif
				return c;
			default:
#ifdef UNIX
				zbitch("Bad data subpacket");
#endif
				return c;
			}
		}
		*buf++ = c;
		crc = UPDC32(c, crc);
	}
#ifdef UNIX
	zbitch("Data subpacket too long");
#endif
	return IZERROR;
}


/*
 * Read a ZMODEM header to hdr, either binary or hex.
 *  On success, set Rxpos and return type of header.
 *   Otherwise return negative on error.
 *   Return  IZERROR instantly if ZCRCW sequence, for fast error recovery.
 */
int
zgethdr()
{
	register int c, n, cancount;

	n = Zrwindow + 19200;	/* Max bytes before start of frame */
	Rxframeind = Rxtype = 0;

startover:
	cancount = 5;
again:
	/* Return immediate IZERROR if ZCRCW sequence seen */
	switch (c = readline(Rxtimeout)) {
	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 = IZERROR;
		/*FALLTHRU*/
			goto fifi;
		default:
			break;
		case CAN:
			if (--cancount <= 0) {
				c = ZCAN; goto fifi;
			}
			goto again;
		}
	/*FALLTHRU*/
	default:
agn2:
		if ( --n == 0) {
#ifdef UNIX
			zbitch("Garbage count exceeded");
#endif
			return(IZERROR);
		}
#ifdef UNIX
		fflush(stderr);
#endif
		goto startover;
	case ZPAD|0200:		/* This is what we want. */
	case ZPAD:		/* This is what we want. */
		break;
	}
	cancount = 5;
splat:
	switch (c = noxrd7()) {
	case ZPAD:
		goto splat;
	case TIMEOUT:
		goto fifi;
	default:
		goto agn2;
	case ZDLE:		/* This is what we want. */
		break;
	}

	switch (c = noxrd7()) {
	case TIMEOUT:
		goto fifi;
	case ZBIN:
		Rxframeind = c;
		c =  zrbhdr();
		break;
#ifdef ADDRLE
	case ZBINR32:
#endif
	case ZBIN32:
		Rxframeind = c;
		c =  zrbhdr32();
		break;
	case ZHEX:
		Rxframeind = c;
		c =  zrhhdr();
		break;
	case CAN:
		goto gotcan;
	default:
		goto agn2;
	}
	Rxpos = Rxhdr[ZP3] & 0377;
	Rxpos = (Rxpos<<8) + (Rxhdr[ZP2] & 0377);
	Rxpos = (Rxpos<<8) + (Rxhdr[ZP1] & 0377);
	Rxpos = (Rxpos<<8) + (Rxhdr[ZP0] & 0377);
fifi:
	switch (c) {
	case GOTCAN:
		c = ZCAN;
	/*FALLTHRU*/
#ifdef UNIX
	case ZNAK:
	case ZCAN:
	case IZERROR:
	case TIMEOUT:
		zperr("Zgethdr: got %s", frametypes[c+FTOFFSET]);
	/*FALLTHRU*/
#endif
	default:
#ifdef DIAGS
		if (c >= -3 && c <= FRTYPES)
			vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
		else
			vfile("zgethdr: %d %lx", c, Rxpos);
#endif
		break;
	}
	return c;
}

/* Receive a binary style header (type and position) */
zrbhdr()
{
	register char *hdr = Rxhdr;
	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) {
#ifdef DIAGS
		zbitch(badcrc);
#endif
		return IZERROR;
	}
	return Rxtype;
}

/* Receive a binary style header (type and position) with 32 bit FCS */
zrbhdr32()
{
	register char *hdr = Rxhdr;
	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) {
#ifdef DIAGS
		zbitch(badcrc);
#endif
		return IZERROR;
	}
	return Rxtype;
}


/* Receive a hex style header (type and position) */
zrhhdr()
{
	register int c;
	register char *hdr = Rxhdr;
	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) {
#ifdef DIAGS
		zbitch(badcrc);
#endif
		return IZERROR;
	}
	switch ( c = readline(1)) {
	case 0215:
	case 015:
	 	/* Throw away possible cr/lf */
		c = readline(1);
	}
	return Rxtype;
}

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

#ifdef DIAGS
	if (Verbose>8)
		vfile("zputhex: %02X", c & 0377);
#endif
	sendline(digits[(c&0xF0)>>4]);
	sendline(digits[(c)&0xF]);
}

/*
 * Send character c with ZMODEM escape sequence encoding.
 *  Escape DLE, XON, XOFF. 
 */
void
zsendline(c)
register c;
#ifdef ZSTAB
{
	register d;

	c &= 0377;
	if ((d = zstable[c])) {
		sendline(ZDLE); c = d;
	}
	sendline(c);
}
#else
{
#ifdef NOFF
	c &= 0377;
	if (c == 0377) {
			sendline(ZDLE);
			c = ZRUB1;	/* Passes the 0140 mask below !! */
	}
#endif
	/* Quick check for non control characters */
	if (c & 0140)
		sendline(c);
	else {
		switch (c &= 0377) {
		case ZDLE:
		case 020:
		case 021:
		case 023:
		case 0220:
		case 0221:
		case 0223:
			sendline(ZDLE);
			c ^= 0100;
			sendline(c);
			break;
		default:
			if (Zctlesc) {
				sendline(ZDLE);
				c ^= 0100;
			}
			sendline(c);
		}
	}
}
#endif

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

	c = zgeth1();
#ifdef DIAGS
	if (Verbose>8)
		vfile("zgethex: %02X", c);
#endif
	return c;
}
zgeth1()
{
	register int c, n;

	if ((c = noxrd7()) < 0)
		return c;
	n = c - '0';
	if (n > 9)
		n -= ('a' - ':');
	if (n & ~0xF)
		return IZERROR;
	if ((c = noxrd7()) < 0)
		return c;
	c -= '0';
	if (c > 9)
		c -= ('a' - ':');
	if (c & ~0xF)
		return IZERROR;
	c += (n<<4);
	return c;
}

/*
 * Read a byte, checking for ZMODEM escape encoding
 *  including CAN*5 which represents a quick abort
 */
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);
		/* DO NOT REMOVE THIS ENTRY!!! */
	case ZRUB0:
		return 0177;
		/* DO NOT REMOVE THIS ENTRY!!! (used for telnet) */
	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;
	}
#ifdef DIAGS
	if (Verbose>1)
		zperr("Bad escape sequence %x", c);
#endif
	return IZERROR;
}

/*
 * Read a character from the modem line with timeout.
 *  Eat parity, XON and XOFF characters.
 */
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;
		/*FALLTHRU*/
		case '\r':
		case '\n':
		case ZDLE:
			return c;
		}
	}
}

/* Store long integer pos in Txhdr */
void
stohdr(pos)
long pos;
{
	Txhdr[ZP0] = (char) pos;
	Txhdr[ZP1] = (char) (pos>>8);
	Txhdr[ZP2] = (char) (pos>>16);
	Txhdr[ZP3] = (char) (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;
}

void
mputs(s)
register char *s;
{
	while (*s)
		sendline(*s++);
#ifdef FLUSH
	flushmo();
#endif
}

/* send cancel string to get the other end to shut up */
void
canit()
{
	static char canistr[] = {
	 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
	};

#ifdef DIAGS
	vfile("Canit");
#endif
	mputs(canistr);
	purgeline();
}

/* End of zm.c */
