/*
 *	 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 */
