xref: /minix3/minix/commands/zmodem/zm.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*
2*433d6423SLionel Sambuc  *   Z M . C
3*433d6423SLionel Sambuc  *    ZMODEM protocol primitives
4*433d6423SLionel Sambuc  *    05-09-88  Chuck Forsberg Omen Technology Inc
5*433d6423SLionel Sambuc  *
6*433d6423SLionel Sambuc  * Entry point Functions:
7*433d6423SLionel Sambuc  *	zsbhdr(type, hdr) send binary header
8*433d6423SLionel Sambuc  *	zshhdr(type, hdr) send hex header
9*433d6423SLionel Sambuc  *	zgethdr(hdr, eflag) receive header - binary or hex
10*433d6423SLionel Sambuc  *	zsdata(buf, len, frameend) send data
11*433d6423SLionel Sambuc  *	zrdata(buf, len) receive data
12*433d6423SLionel Sambuc  *	stohdr(pos) store position data in Txhdr
13*433d6423SLionel Sambuc  *	long rclhdr(hdr) recover position offset from header
14*433d6423SLionel Sambuc  */
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc #ifndef CANFDX
17*433d6423SLionel Sambuc #include "zmodem.h"
18*433d6423SLionel Sambuc #endif
19*433d6423SLionel Sambuc int Rxtimeout = 100;		/* Tenths of seconds to wait for something */
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc #ifndef UNSL
22*433d6423SLionel Sambuc #define UNSL
23*433d6423SLionel Sambuc #endif
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc /* Globals used by ZMODEM functions */
27*433d6423SLionel Sambuc int Rxframeind;		/* ZBIN ZBIN32, or ZHEX type of frame received */
28*433d6423SLionel Sambuc int Rxtype;		/* Type of header received */
29*433d6423SLionel Sambuc int Rxcount;		/* Count of data bytes received */
30*433d6423SLionel Sambuc char Rxhdr[4];		/* Received header */
31*433d6423SLionel Sambuc char Txhdr[4];		/* Transmitted header */
32*433d6423SLionel Sambuc long Rxpos;		/* Received file position */
33*433d6423SLionel Sambuc long Txpos;		/* Transmitted file position */
34*433d6423SLionel Sambuc int Txfcs32;		/* TURE means send binary frames with 32 bit FCS */
35*433d6423SLionel Sambuc int Crc32t;		/* Display flag indicating 32 bit CRC being sent */
36*433d6423SLionel Sambuc int Crc32;		/* Display flag indicating 32 bit CRC being received */
37*433d6423SLionel Sambuc int Znulls;		/* Number of nulls to send at beginning of ZDATA hdr */
38*433d6423SLionel Sambuc char Attn[ZATTNLEN+1];	/* Attention string rx sends to tx on err */
39*433d6423SLionel Sambuc 
40*433d6423SLionel Sambuc static int lastsent;	/* Last char we sent */
41*433d6423SLionel Sambuc static int Not8bit;	/* Seven bits seen on header */
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc static char *frametypes[] = {
44*433d6423SLionel Sambuc 	"Carrier Lost",		/* -3 */
45*433d6423SLionel Sambuc 	"TIMEOUT",		/* -2 */
46*433d6423SLionel Sambuc 	"ERROR",		/* -1 */
47*433d6423SLionel Sambuc #define FTOFFSET 3
48*433d6423SLionel Sambuc 	"ZRQINIT",
49*433d6423SLionel Sambuc 	"ZRINIT",
50*433d6423SLionel Sambuc 	"ZSINIT",
51*433d6423SLionel Sambuc 	"ZACK",
52*433d6423SLionel Sambuc 	"ZFILE",
53*433d6423SLionel Sambuc 	"ZSKIP",
54*433d6423SLionel Sambuc 	"ZNAK",
55*433d6423SLionel Sambuc 	"ZABORT",
56*433d6423SLionel Sambuc 	"ZFIN",
57*433d6423SLionel Sambuc 	"ZRPOS",
58*433d6423SLionel Sambuc 	"ZDATA",
59*433d6423SLionel Sambuc 	"ZEOF",
60*433d6423SLionel Sambuc 	"ZFERR",
61*433d6423SLionel Sambuc 	"ZCRC",
62*433d6423SLionel Sambuc 	"ZCHALLENGE",
63*433d6423SLionel Sambuc 	"ZCOMPL",
64*433d6423SLionel Sambuc 	"ZCAN",
65*433d6423SLionel Sambuc 	"ZFREECNT",
66*433d6423SLionel Sambuc 	"ZCOMMAND",
67*433d6423SLionel Sambuc 	"ZSTDERR",
68*433d6423SLionel Sambuc 	"xxxxx"
69*433d6423SLionel Sambuc #define FRTYPES 22	/* Total number of frame types in this array */
70*433d6423SLionel Sambuc 			/*  not including psuedo negative entries */
71*433d6423SLionel Sambuc };
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc static char badcrc[] = "Bad CRC";
74*433d6423SLionel Sambuc 
75*433d6423SLionel Sambuc /* Send ZMODEM binary header hdr of type type */
zsbhdr(int type,char * hdr)76*433d6423SLionel Sambuc void zsbhdr(int type, char *hdr)
77*433d6423SLionel Sambuc {
78*433d6423SLionel Sambuc 	register int n;
79*433d6423SLionel Sambuc 	register unsigned short crc;
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc 	vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
82*433d6423SLionel Sambuc 	if (type == ZDATA)
83*433d6423SLionel Sambuc 		for (n = Znulls; --n >=0; )
84*433d6423SLionel Sambuc 			xsendline(0);
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc 	xsendline(ZPAD); xsendline(ZDLE);
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc 	if ((Crc32t=Txfcs32))
89*433d6423SLionel Sambuc 		zsbh32(hdr, type);
90*433d6423SLionel Sambuc 	else {
91*433d6423SLionel Sambuc 		xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
92*433d6423SLionel Sambuc 
93*433d6423SLionel Sambuc 		for (n=4; --n >= 0; ++hdr) {
94*433d6423SLionel Sambuc 			zsendline(*hdr);
95*433d6423SLionel Sambuc 			crc = updcrc((0377& *hdr), crc);
96*433d6423SLionel Sambuc 		}
97*433d6423SLionel Sambuc 		crc = updcrc(0,updcrc(0,crc));
98*433d6423SLionel Sambuc 		zsendline(crc>>8);
99*433d6423SLionel Sambuc 		zsendline(crc);
100*433d6423SLionel Sambuc 	}
101*433d6423SLionel Sambuc 	if (type != ZDATA)
102*433d6423SLionel Sambuc 		flushmo();
103*433d6423SLionel Sambuc }
104*433d6423SLionel Sambuc 
105*433d6423SLionel Sambuc 
106*433d6423SLionel Sambuc /* Send ZMODEM binary header hdr of type type */
zsbh32(char * hdr,int type)107*433d6423SLionel Sambuc void zsbh32(char *hdr, int type)
108*433d6423SLionel Sambuc {
109*433d6423SLionel Sambuc 	register int n;
110*433d6423SLionel Sambuc 	register UNSL long crc;
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc 	xsendline(ZBIN32);  zsendline(type);
113*433d6423SLionel Sambuc 	crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc 	for (n=4; --n >= 0; ++hdr) {
116*433d6423SLionel Sambuc 		crc = UPDC32((0377 & *hdr), crc);
117*433d6423SLionel Sambuc 		zsendline(*hdr);
118*433d6423SLionel Sambuc 	}
119*433d6423SLionel Sambuc 	crc = ~crc;
120*433d6423SLionel Sambuc 	for (n=4; --n >= 0;) {
121*433d6423SLionel Sambuc 		zsendline((int)crc);
122*433d6423SLionel Sambuc 		crc >>= 8;
123*433d6423SLionel Sambuc 	}
124*433d6423SLionel Sambuc }
125*433d6423SLionel Sambuc 
126*433d6423SLionel Sambuc /* Send ZMODEM HEX header hdr of type type */
zshhdr(int type,char * hdr)127*433d6423SLionel Sambuc void zshhdr(int type, char *hdr)
128*433d6423SLionel Sambuc {
129*433d6423SLionel Sambuc 	register int n;
130*433d6423SLionel Sambuc 	register unsigned short crc;
131*433d6423SLionel Sambuc 
132*433d6423SLionel Sambuc 	vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
133*433d6423SLionel Sambuc 	sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
134*433d6423SLionel Sambuc 	zputhex(type);
135*433d6423SLionel Sambuc 	Crc32t = 0;
136*433d6423SLionel Sambuc 
137*433d6423SLionel Sambuc 	crc = updcrc(type, 0);
138*433d6423SLionel Sambuc 	for (n=4; --n >= 0; ++hdr) {
139*433d6423SLionel Sambuc 		zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
140*433d6423SLionel Sambuc 	}
141*433d6423SLionel Sambuc 	crc = updcrc(0,updcrc(0,crc));
142*433d6423SLionel Sambuc 	zputhex(crc>>8); zputhex(crc);
143*433d6423SLionel Sambuc 
144*433d6423SLionel Sambuc 	/* Make it printable on remote machine */
145*433d6423SLionel Sambuc 	sendline(015); sendline(0212);
146*433d6423SLionel Sambuc 	/*
147*433d6423SLionel Sambuc 	 * Uncork the remote in case a fake XOFF has stopped data flow
148*433d6423SLionel Sambuc 	 */
149*433d6423SLionel Sambuc 	if (type != ZFIN && type != ZACK)
150*433d6423SLionel Sambuc 		sendline(021);
151*433d6423SLionel Sambuc 	flushmo();
152*433d6423SLionel Sambuc }
153*433d6423SLionel Sambuc 
154*433d6423SLionel Sambuc /*
155*433d6423SLionel Sambuc  * Send binary array buf of length length, with ending ZDLE sequence frameend
156*433d6423SLionel Sambuc  */
157*433d6423SLionel Sambuc static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
158*433d6423SLionel Sambuc 
zsdata(char * buf,int length,int frameend)159*433d6423SLionel Sambuc void zsdata(char *buf, int length, int frameend)
160*433d6423SLionel Sambuc {
161*433d6423SLionel Sambuc 	register unsigned short crc;
162*433d6423SLionel Sambuc 
163*433d6423SLionel Sambuc 	vfile("zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]);
164*433d6423SLionel Sambuc 	if (Crc32t)
165*433d6423SLionel Sambuc 		zsda32(buf, length, frameend);
166*433d6423SLionel Sambuc 	else {
167*433d6423SLionel Sambuc 		crc = 0;
168*433d6423SLionel Sambuc 		for (;--length >= 0; ++buf) {
169*433d6423SLionel Sambuc 			zsendline(*buf); crc = updcrc((0377 & *buf), crc);
170*433d6423SLionel Sambuc 		}
171*433d6423SLionel Sambuc 		xsendline(ZDLE); xsendline(frameend);
172*433d6423SLionel Sambuc 		crc = updcrc(frameend, crc);
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc 		crc = updcrc(0,updcrc(0,crc));
175*433d6423SLionel Sambuc 		zsendline(crc>>8); zsendline(crc);
176*433d6423SLionel Sambuc 	}
177*433d6423SLionel Sambuc 	if (frameend == ZCRCW) {
178*433d6423SLionel Sambuc 		xsendline(XON);  flushmo();
179*433d6423SLionel Sambuc 	}
180*433d6423SLionel Sambuc }
181*433d6423SLionel Sambuc 
zsda32(char * buf,int length,int frameend)182*433d6423SLionel Sambuc void zsda32(char *buf, int length, int frameend)
183*433d6423SLionel Sambuc {
184*433d6423SLionel Sambuc 	register int c;
185*433d6423SLionel Sambuc 	register UNSL long crc;
186*433d6423SLionel Sambuc 
187*433d6423SLionel Sambuc 	crc = 0xFFFFFFFFL;
188*433d6423SLionel Sambuc 	for (;--length >= 0; ++buf) {
189*433d6423SLionel Sambuc 		c = *buf & 0377;
190*433d6423SLionel Sambuc 		if (c & 0140)
191*433d6423SLionel Sambuc 			xsendline(lastsent = c);
192*433d6423SLionel Sambuc 		else
193*433d6423SLionel Sambuc 			zsendline(c);
194*433d6423SLionel Sambuc 		crc = UPDC32(c, crc);
195*433d6423SLionel Sambuc 	}
196*433d6423SLionel Sambuc 	xsendline(ZDLE); xsendline(frameend);
197*433d6423SLionel Sambuc 	crc = UPDC32(frameend, crc);
198*433d6423SLionel Sambuc 
199*433d6423SLionel Sambuc 	crc = ~crc;
200*433d6423SLionel Sambuc 	for (length=4; --length >= 0;) {
201*433d6423SLionel Sambuc 		zsendline((int)crc);  crc >>= 8;
202*433d6423SLionel Sambuc 	}
203*433d6423SLionel Sambuc }
204*433d6423SLionel Sambuc 
205*433d6423SLionel Sambuc /*
206*433d6423SLionel Sambuc  * Receive array buf of max length with ending ZDLE sequence
207*433d6423SLionel Sambuc  *  and CRC.  Returns the ending character or error code.
208*433d6423SLionel Sambuc  *  NB: On errors may store length+1 bytes!
209*433d6423SLionel Sambuc  */
zrdata(char * buf,int length)210*433d6423SLionel Sambuc int zrdata(char *buf, int length)
211*433d6423SLionel Sambuc {
212*433d6423SLionel Sambuc 	register int c;
213*433d6423SLionel Sambuc 	register unsigned short crc;
214*433d6423SLionel Sambuc 	register char *end;
215*433d6423SLionel Sambuc 	register int d;
216*433d6423SLionel Sambuc 
217*433d6423SLionel Sambuc 	if (Rxframeind == ZBIN32)
218*433d6423SLionel Sambuc 		return zrdat32(buf, length);
219*433d6423SLionel Sambuc 
220*433d6423SLionel Sambuc 	crc = Rxcount = 0;  end = buf + length;
221*433d6423SLionel Sambuc 	while (buf <= end) {
222*433d6423SLionel Sambuc 		if ((c = zdlread()) & ~0377) {
223*433d6423SLionel Sambuc crcfoo:
224*433d6423SLionel Sambuc 			switch (c) {
225*433d6423SLionel Sambuc 			case GOTCRCE:
226*433d6423SLionel Sambuc 			case GOTCRCG:
227*433d6423SLionel Sambuc 			case GOTCRCQ:
228*433d6423SLionel Sambuc 			case GOTCRCW:
229*433d6423SLionel Sambuc 				crc = updcrc((((d=c))&0377), crc);
230*433d6423SLionel Sambuc 				if ((c = zdlread()) & ~0377)
231*433d6423SLionel Sambuc 					goto crcfoo;
232*433d6423SLionel Sambuc 				crc = updcrc(c, crc);
233*433d6423SLionel Sambuc 				if ((c = zdlread()) & ~0377)
234*433d6423SLionel Sambuc 					goto crcfoo;
235*433d6423SLionel Sambuc 				crc = updcrc(c, crc);
236*433d6423SLionel Sambuc 				if (crc & 0xFFFF) {
237*433d6423SLionel Sambuc 					zperr(badcrc);
238*433d6423SLionel Sambuc 					return ERROR;
239*433d6423SLionel Sambuc 				}
240*433d6423SLionel Sambuc 				Rxcount = length - (end - buf);
241*433d6423SLionel Sambuc 				vfile("zrdata: %d  %s", Rxcount,
242*433d6423SLionel Sambuc 				 Zendnames[(d-GOTCRCE)&3]);
243*433d6423SLionel Sambuc 				return d;
244*433d6423SLionel Sambuc 			case GOTCAN:
245*433d6423SLionel Sambuc 				zperr("Sender Canceled");
246*433d6423SLionel Sambuc 				return ZCAN;
247*433d6423SLionel Sambuc 			case TIMEOUT:
248*433d6423SLionel Sambuc 				zperr("TIMEOUT");
249*433d6423SLionel Sambuc 				return c;
250*433d6423SLionel Sambuc 			default:
251*433d6423SLionel Sambuc 				zperr("Bad data subpacket");
252*433d6423SLionel Sambuc 				return c;
253*433d6423SLionel Sambuc 			}
254*433d6423SLionel Sambuc 		}
255*433d6423SLionel Sambuc 		*buf++ = c;
256*433d6423SLionel Sambuc 		crc = updcrc(c, crc);
257*433d6423SLionel Sambuc 	}
258*433d6423SLionel Sambuc 	zperr("Data subpacket too long");
259*433d6423SLionel Sambuc 	return ERROR;
260*433d6423SLionel Sambuc }
261*433d6423SLionel Sambuc 
zrdat32(char * buf,int length)262*433d6423SLionel Sambuc int zrdat32(char *buf, int length)
263*433d6423SLionel Sambuc {
264*433d6423SLionel Sambuc 	register int c;
265*433d6423SLionel Sambuc 	register UNSL long crc;
266*433d6423SLionel Sambuc 	register char *end;
267*433d6423SLionel Sambuc 	register int d;
268*433d6423SLionel Sambuc 
269*433d6423SLionel Sambuc 	crc = 0xFFFFFFFFL;  Rxcount = 0;  end = buf + length;
270*433d6423SLionel Sambuc 	while (buf <= end) {
271*433d6423SLionel Sambuc 		if ((c = zdlread()) & ~0377) {
272*433d6423SLionel Sambuc crcfoo:
273*433d6423SLionel Sambuc 			switch (c) {
274*433d6423SLionel Sambuc 			case GOTCRCE:
275*433d6423SLionel Sambuc 			case GOTCRCG:
276*433d6423SLionel Sambuc 			case GOTCRCQ:
277*433d6423SLionel Sambuc 			case GOTCRCW:
278*433d6423SLionel Sambuc 				d = c;  c &= 0377;
279*433d6423SLionel Sambuc 				crc = UPDC32(c, crc);
280*433d6423SLionel Sambuc 				if ((c = zdlread()) & ~0377)
281*433d6423SLionel Sambuc 					goto crcfoo;
282*433d6423SLionel Sambuc 				crc = UPDC32(c, crc);
283*433d6423SLionel Sambuc 				if ((c = zdlread()) & ~0377)
284*433d6423SLionel Sambuc 					goto crcfoo;
285*433d6423SLionel Sambuc 				crc = UPDC32(c, crc);
286*433d6423SLionel Sambuc 				if ((c = zdlread()) & ~0377)
287*433d6423SLionel Sambuc 					goto crcfoo;
288*433d6423SLionel Sambuc 				crc = UPDC32(c, crc);
289*433d6423SLionel Sambuc 				if ((c = zdlread()) & ~0377)
290*433d6423SLionel Sambuc 					goto crcfoo;
291*433d6423SLionel Sambuc 				crc = UPDC32(c, crc);
292*433d6423SLionel Sambuc 				if (crc != 0xDEBB20E3) {
293*433d6423SLionel Sambuc 					zperr(badcrc);
294*433d6423SLionel Sambuc 					return ERROR;
295*433d6423SLionel Sambuc 				}
296*433d6423SLionel Sambuc 				Rxcount = length - (end - buf);
297*433d6423SLionel Sambuc 				vfile("zrdat32: %d %s", Rxcount,
298*433d6423SLionel Sambuc 				 Zendnames[(d-GOTCRCE)&3]);
299*433d6423SLionel Sambuc 				return d;
300*433d6423SLionel Sambuc 			case GOTCAN:
301*433d6423SLionel Sambuc 				zperr("Sender Canceled");
302*433d6423SLionel Sambuc 				return ZCAN;
303*433d6423SLionel Sambuc 			case TIMEOUT:
304*433d6423SLionel Sambuc 				zperr("TIMEOUT");
305*433d6423SLionel Sambuc 				return c;
306*433d6423SLionel Sambuc 			default:
307*433d6423SLionel Sambuc 				zperr("Bad data subpacket");
308*433d6423SLionel Sambuc 				return c;
309*433d6423SLionel Sambuc 			}
310*433d6423SLionel Sambuc 		}
311*433d6423SLionel Sambuc 		*buf++ = c;
312*433d6423SLionel Sambuc 		crc = UPDC32(c, crc);
313*433d6423SLionel Sambuc 	}
314*433d6423SLionel Sambuc 	zperr("Data subpacket too long");
315*433d6423SLionel Sambuc 	return ERROR;
316*433d6423SLionel Sambuc }
317*433d6423SLionel Sambuc 
318*433d6423SLionel Sambuc 
319*433d6423SLionel Sambuc /*
320*433d6423SLionel Sambuc  * Read a ZMODEM header to hdr, either binary or hex.
321*433d6423SLionel Sambuc  *  eflag controls local display of non zmodem characters:
322*433d6423SLionel Sambuc  *	0:  no display
323*433d6423SLionel Sambuc  *	1:  display printing characters only
324*433d6423SLionel Sambuc  *	2:  display all non ZMODEM characters
325*433d6423SLionel Sambuc  *  On success, set Zmodem to 1, set Rxpos and return type of header.
326*433d6423SLionel Sambuc  *   Otherwise return negative on error.
327*433d6423SLionel Sambuc  *   Return ERROR instantly if ZCRCW sequence, for fast error recovery.
328*433d6423SLionel Sambuc  */
zgethdr(char * hdr,int eflag)329*433d6423SLionel Sambuc int zgethdr(char *hdr, int eflag)
330*433d6423SLionel Sambuc {
331*433d6423SLionel Sambuc 	register int c, n, cancount;
332*433d6423SLionel Sambuc 
333*433d6423SLionel Sambuc 	n = Zrwindow + Baudrate;	/* Max bytes before start of frame */
334*433d6423SLionel Sambuc 	Rxframeind = Rxtype = 0;
335*433d6423SLionel Sambuc 
336*433d6423SLionel Sambuc startover:
337*433d6423SLionel Sambuc 	cancount = 5;
338*433d6423SLionel Sambuc again:
339*433d6423SLionel Sambuc 	/* Return immediate ERROR if ZCRCW sequence seen */
340*433d6423SLionel Sambuc 	switch (c = readline(Rxtimeout)) {
341*433d6423SLionel Sambuc 	case RCDO:
342*433d6423SLionel Sambuc 	case TIMEOUT:
343*433d6423SLionel Sambuc 		goto fifi;
344*433d6423SLionel Sambuc 	case CAN:
345*433d6423SLionel Sambuc gotcan:
346*433d6423SLionel Sambuc 		if (--cancount <= 0) {
347*433d6423SLionel Sambuc 			c = ZCAN; goto fifi;
348*433d6423SLionel Sambuc 		}
349*433d6423SLionel Sambuc 		switch (c = readline(1)) {
350*433d6423SLionel Sambuc 		case TIMEOUT:
351*433d6423SLionel Sambuc 			goto again;
352*433d6423SLionel Sambuc 		case ZCRCW:
353*433d6423SLionel Sambuc 			c = ERROR;
354*433d6423SLionel Sambuc 		/* **** FALL THRU TO **** */
355*433d6423SLionel Sambuc 		case RCDO:
356*433d6423SLionel Sambuc 			goto fifi;
357*433d6423SLionel Sambuc 		default:
358*433d6423SLionel Sambuc 			break;
359*433d6423SLionel Sambuc 		case CAN:
360*433d6423SLionel Sambuc 			if (--cancount <= 0) {
361*433d6423SLionel Sambuc 				c = ZCAN; goto fifi;
362*433d6423SLionel Sambuc 			}
363*433d6423SLionel Sambuc 			goto again;
364*433d6423SLionel Sambuc 		}
365*433d6423SLionel Sambuc 	/* **** FALL THRU TO **** */
366*433d6423SLionel Sambuc 	default:
367*433d6423SLionel Sambuc agn2:
368*433d6423SLionel Sambuc 		if ( --n == 0) {
369*433d6423SLionel Sambuc 			zperr("Garbage count exceeded");
370*433d6423SLionel Sambuc 			return(ERROR);
371*433d6423SLionel Sambuc 		}
372*433d6423SLionel Sambuc 		if (eflag && ((c &= 0177) & 0140))
373*433d6423SLionel Sambuc 			bttyout(c);
374*433d6423SLionel Sambuc 		else if (eflag > 1)
375*433d6423SLionel Sambuc 			bttyout(c);
376*433d6423SLionel Sambuc #ifdef UNIX
377*433d6423SLionel Sambuc 		fflush(stderr);
378*433d6423SLionel Sambuc #endif
379*433d6423SLionel Sambuc 		goto startover;
380*433d6423SLionel Sambuc 	case ZPAD|0200:		/* This is what we want. */
381*433d6423SLionel Sambuc 		Not8bit = c;
382*433d6423SLionel Sambuc 	case ZPAD:		/* This is what we want. */
383*433d6423SLionel Sambuc 		break;
384*433d6423SLionel Sambuc 	}
385*433d6423SLionel Sambuc 	cancount = 5;
386*433d6423SLionel Sambuc splat:
387*433d6423SLionel Sambuc 	switch (c = noxrd7()) {
388*433d6423SLionel Sambuc 	case ZPAD:
389*433d6423SLionel Sambuc 		goto splat;
390*433d6423SLionel Sambuc 	case RCDO:
391*433d6423SLionel Sambuc 	case TIMEOUT:
392*433d6423SLionel Sambuc 		goto fifi;
393*433d6423SLionel Sambuc 	default:
394*433d6423SLionel Sambuc 		goto agn2;
395*433d6423SLionel Sambuc 	case ZDLE:		/* This is what we want. */
396*433d6423SLionel Sambuc 		break;
397*433d6423SLionel Sambuc 	}
398*433d6423SLionel Sambuc 
399*433d6423SLionel Sambuc 	switch (c = noxrd7()) {
400*433d6423SLionel Sambuc 	case RCDO:
401*433d6423SLionel Sambuc 	case TIMEOUT:
402*433d6423SLionel Sambuc 		goto fifi;
403*433d6423SLionel Sambuc 	case ZBIN:
404*433d6423SLionel Sambuc 		Rxframeind = ZBIN;  Crc32 = FALSE;
405*433d6423SLionel Sambuc 		c =  zrbhdr(hdr);
406*433d6423SLionel Sambuc 		break;
407*433d6423SLionel Sambuc 	case ZBIN32:
408*433d6423SLionel Sambuc 		Crc32 = Rxframeind = ZBIN32;
409*433d6423SLionel Sambuc 		c =  zrbhdr32(hdr);
410*433d6423SLionel Sambuc 		break;
411*433d6423SLionel Sambuc 	case ZHEX:
412*433d6423SLionel Sambuc 		Rxframeind = ZHEX;  Crc32 = FALSE;
413*433d6423SLionel Sambuc 		c =  zrhhdr(hdr);
414*433d6423SLionel Sambuc 		break;
415*433d6423SLionel Sambuc 	case CAN:
416*433d6423SLionel Sambuc 		goto gotcan;
417*433d6423SLionel Sambuc 	default:
418*433d6423SLionel Sambuc 		goto agn2;
419*433d6423SLionel Sambuc 	}
420*433d6423SLionel Sambuc 	Rxpos = hdr[ZP3] & 0377;
421*433d6423SLionel Sambuc 	Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
422*433d6423SLionel Sambuc 	Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
423*433d6423SLionel Sambuc 	Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
424*433d6423SLionel Sambuc fifi:
425*433d6423SLionel Sambuc 	switch (c) {
426*433d6423SLionel Sambuc 	case GOTCAN:
427*433d6423SLionel Sambuc 		c = ZCAN;
428*433d6423SLionel Sambuc 	/* **** FALL THRU TO **** */
429*433d6423SLionel Sambuc 	case ZNAK:
430*433d6423SLionel Sambuc 	case ZCAN:
431*433d6423SLionel Sambuc 	case ERROR:
432*433d6423SLionel Sambuc 	case TIMEOUT:
433*433d6423SLionel Sambuc 	case RCDO:
434*433d6423SLionel Sambuc 		zperr("Got %s", frametypes[c+FTOFFSET]);
435*433d6423SLionel Sambuc 	/* **** FALL THRU TO **** */
436*433d6423SLionel Sambuc 	default:
437*433d6423SLionel Sambuc 		if (c >= -3 && c <= FRTYPES)
438*433d6423SLionel Sambuc 			vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
439*433d6423SLionel Sambuc 		else
440*433d6423SLionel Sambuc 			vfile("zgethdr: %d %lx", c, Rxpos);
441*433d6423SLionel Sambuc 	}
442*433d6423SLionel Sambuc 	return c;
443*433d6423SLionel Sambuc }
444*433d6423SLionel Sambuc 
445*433d6423SLionel Sambuc /* Receive a binary style header (type and position) */
zrbhdr(char * hdr)446*433d6423SLionel Sambuc int zrbhdr(char *hdr)
447*433d6423SLionel Sambuc {
448*433d6423SLionel Sambuc 	register int c, n;
449*433d6423SLionel Sambuc 	register unsigned short crc;
450*433d6423SLionel Sambuc 
451*433d6423SLionel Sambuc 	if ((c = zdlread()) & ~0377)
452*433d6423SLionel Sambuc 		return c;
453*433d6423SLionel Sambuc 	Rxtype = c;
454*433d6423SLionel Sambuc 	crc = updcrc(c, 0);
455*433d6423SLionel Sambuc 
456*433d6423SLionel Sambuc 	for (n=4; --n >= 0; ++hdr) {
457*433d6423SLionel Sambuc 		if ((c = zdlread()) & ~0377)
458*433d6423SLionel Sambuc 			return c;
459*433d6423SLionel Sambuc 		crc = updcrc(c, crc);
460*433d6423SLionel Sambuc 		*hdr = c;
461*433d6423SLionel Sambuc 	}
462*433d6423SLionel Sambuc 	if ((c = zdlread()) & ~0377)
463*433d6423SLionel Sambuc 		return c;
464*433d6423SLionel Sambuc 	crc = updcrc(c, crc);
465*433d6423SLionel Sambuc 	if ((c = zdlread()) & ~0377)
466*433d6423SLionel Sambuc 		return c;
467*433d6423SLionel Sambuc 	crc = updcrc(c, crc);
468*433d6423SLionel Sambuc 	if (crc & 0xFFFF) {
469*433d6423SLionel Sambuc 		zperr(badcrc);
470*433d6423SLionel Sambuc 		return ERROR;
471*433d6423SLionel Sambuc 	}
472*433d6423SLionel Sambuc #ifdef ZMODEM
473*433d6423SLionel Sambuc 	Protocol = ZMODEM;
474*433d6423SLionel Sambuc #endif
475*433d6423SLionel Sambuc 	Zmodem = 1;
476*433d6423SLionel Sambuc 	return Rxtype;
477*433d6423SLionel Sambuc }
478*433d6423SLionel Sambuc 
479*433d6423SLionel Sambuc /* Receive a binary style header (type and position) with 32 bit FCS */
zrbhdr32(char * hdr)480*433d6423SLionel Sambuc int zrbhdr32(char *hdr)
481*433d6423SLionel Sambuc {
482*433d6423SLionel Sambuc 	register int c, n;
483*433d6423SLionel Sambuc 	register UNSL long crc;
484*433d6423SLionel Sambuc 
485*433d6423SLionel Sambuc 	if ((c = zdlread()) & ~0377)
486*433d6423SLionel Sambuc 		return c;
487*433d6423SLionel Sambuc 	Rxtype = c;
488*433d6423SLionel Sambuc 	crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
489*433d6423SLionel Sambuc #ifdef DEBUGZ
490*433d6423SLionel Sambuc 	vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
491*433d6423SLionel Sambuc #endif
492*433d6423SLionel Sambuc 
493*433d6423SLionel Sambuc 	for (n=4; --n >= 0; ++hdr) {
494*433d6423SLionel Sambuc 		if ((c = zdlread()) & ~0377)
495*433d6423SLionel Sambuc 			return c;
496*433d6423SLionel Sambuc 		crc = UPDC32(c, crc);
497*433d6423SLionel Sambuc 		*hdr = c;
498*433d6423SLionel Sambuc #ifdef DEBUGZ
499*433d6423SLionel Sambuc 		vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
500*433d6423SLionel Sambuc #endif
501*433d6423SLionel Sambuc 	}
502*433d6423SLionel Sambuc 	for (n=4; --n >= 0;) {
503*433d6423SLionel Sambuc 		if ((c = zdlread()) & ~0377)
504*433d6423SLionel Sambuc 			return c;
505*433d6423SLionel Sambuc 		crc = UPDC32(c, crc);
506*433d6423SLionel Sambuc #ifdef DEBUGZ
507*433d6423SLionel Sambuc 		vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
508*433d6423SLionel Sambuc #endif
509*433d6423SLionel Sambuc 	}
510*433d6423SLionel Sambuc 	if (crc != 0xDEBB20E3) {
511*433d6423SLionel Sambuc 		zperr(badcrc);
512*433d6423SLionel Sambuc 		return ERROR;
513*433d6423SLionel Sambuc 	}
514*433d6423SLionel Sambuc #ifdef ZMODEM
515*433d6423SLionel Sambuc 	Protocol = ZMODEM;
516*433d6423SLionel Sambuc #endif
517*433d6423SLionel Sambuc 	Zmodem = 1;
518*433d6423SLionel Sambuc 	return Rxtype;
519*433d6423SLionel Sambuc }
520*433d6423SLionel Sambuc 
521*433d6423SLionel Sambuc 
522*433d6423SLionel Sambuc /* Receive a hex style header (type and position) */
zrhhdr(char * hdr)523*433d6423SLionel Sambuc int zrhhdr(char *hdr)
524*433d6423SLionel Sambuc {
525*433d6423SLionel Sambuc 	register int c;
526*433d6423SLionel Sambuc 	register unsigned short crc;
527*433d6423SLionel Sambuc 	register int n;
528*433d6423SLionel Sambuc 
529*433d6423SLionel Sambuc 	if ((c = zgethex()) < 0)
530*433d6423SLionel Sambuc 		return c;
531*433d6423SLionel Sambuc 	Rxtype = c;
532*433d6423SLionel Sambuc 	crc = updcrc(c, 0);
533*433d6423SLionel Sambuc 
534*433d6423SLionel Sambuc 	for (n=4; --n >= 0; ++hdr) {
535*433d6423SLionel Sambuc 		if ((c = zgethex()) < 0)
536*433d6423SLionel Sambuc 			return c;
537*433d6423SLionel Sambuc 		crc = updcrc(c, crc);
538*433d6423SLionel Sambuc 		*hdr = c;
539*433d6423SLionel Sambuc 	}
540*433d6423SLionel Sambuc 	if ((c = zgethex()) < 0)
541*433d6423SLionel Sambuc 		return c;
542*433d6423SLionel Sambuc 	crc = updcrc(c, crc);
543*433d6423SLionel Sambuc 	if ((c = zgethex()) < 0)
544*433d6423SLionel Sambuc 		return c;
545*433d6423SLionel Sambuc 	crc = updcrc(c, crc);
546*433d6423SLionel Sambuc 	if (crc & 0xFFFF) {
547*433d6423SLionel Sambuc 		zperr(badcrc); return ERROR;
548*433d6423SLionel Sambuc 	}
549*433d6423SLionel Sambuc 	switch ( c = readline(1)) {
550*433d6423SLionel Sambuc 	case 0215:
551*433d6423SLionel Sambuc 		Not8bit = c;
552*433d6423SLionel Sambuc 		/* **** FALL THRU TO **** */
553*433d6423SLionel Sambuc 	case 015:
554*433d6423SLionel Sambuc 	 	/* Throw away possible cr/lf */
555*433d6423SLionel Sambuc 		switch (c = readline(1)) {
556*433d6423SLionel Sambuc 		case 012:
557*433d6423SLionel Sambuc 			Not8bit |= c;
558*433d6423SLionel Sambuc 		}
559*433d6423SLionel Sambuc 	}
560*433d6423SLionel Sambuc #ifdef ZMODEM
561*433d6423SLionel Sambuc 	Protocol = ZMODEM;
562*433d6423SLionel Sambuc #endif
563*433d6423SLionel Sambuc 	Zmodem = 1; return Rxtype;
564*433d6423SLionel Sambuc }
565*433d6423SLionel Sambuc 
566*433d6423SLionel Sambuc /* Send a byte as two hex digits */
zputhex(int c)567*433d6423SLionel Sambuc void zputhex(int c)
568*433d6423SLionel Sambuc {
569*433d6423SLionel Sambuc 	static char	digits[]	= "0123456789abcdef";
570*433d6423SLionel Sambuc 
571*433d6423SLionel Sambuc 	if (Verbose>8)
572*433d6423SLionel Sambuc 		vfile("zputhex: %02X", c);
573*433d6423SLionel Sambuc 	sendline(digits[(c&0xF0)>>4]);
574*433d6423SLionel Sambuc 	sendline(digits[(c)&0xF]);
575*433d6423SLionel Sambuc }
576*433d6423SLionel Sambuc 
577*433d6423SLionel Sambuc /*
578*433d6423SLionel Sambuc  * Send character c with ZMODEM escape sequence encoding.
579*433d6423SLionel Sambuc  *  Escape XON, XOFF. Escape CR following @ (Telenet net escape)
580*433d6423SLionel Sambuc  */
zsendline(int c)581*433d6423SLionel Sambuc void zsendline(int c)
582*433d6423SLionel Sambuc {
583*433d6423SLionel Sambuc 
584*433d6423SLionel Sambuc 	/* Quick check for non control characters */
585*433d6423SLionel Sambuc 	if (c & 0140)
586*433d6423SLionel Sambuc 		xsendline(lastsent = c);
587*433d6423SLionel Sambuc 	else {
588*433d6423SLionel Sambuc 		switch (c &= 0377) {
589*433d6423SLionel Sambuc 		case ZDLE:
590*433d6423SLionel Sambuc 			xsendline(ZDLE);
591*433d6423SLionel Sambuc 			xsendline (lastsent = (c ^= 0100));
592*433d6423SLionel Sambuc 			break;
593*433d6423SLionel Sambuc 		case 015:
594*433d6423SLionel Sambuc 		case 0215:
595*433d6423SLionel Sambuc 			if (!Zctlesc && (lastsent & 0177) != '@')
596*433d6423SLionel Sambuc 				goto sendit;
597*433d6423SLionel Sambuc 		/* **** FALL THRU TO **** */
598*433d6423SLionel Sambuc 		case 020:
599*433d6423SLionel Sambuc 		case 021:
600*433d6423SLionel Sambuc 		case 023:
601*433d6423SLionel Sambuc 		case 0220:
602*433d6423SLionel Sambuc 		case 0221:
603*433d6423SLionel Sambuc 		case 0223:
604*433d6423SLionel Sambuc 			xsendline(ZDLE);
605*433d6423SLionel Sambuc 			c ^= 0100;
606*433d6423SLionel Sambuc 	sendit:
607*433d6423SLionel Sambuc 			xsendline(lastsent = c);
608*433d6423SLionel Sambuc 			break;
609*433d6423SLionel Sambuc 		default:
610*433d6423SLionel Sambuc 			if (Zctlesc && ! (c & 0140)) {
611*433d6423SLionel Sambuc 				xsendline(ZDLE);
612*433d6423SLionel Sambuc 				c ^= 0100;
613*433d6423SLionel Sambuc 			}
614*433d6423SLionel Sambuc 			xsendline(lastsent = c);
615*433d6423SLionel Sambuc 		}
616*433d6423SLionel Sambuc 	}
617*433d6423SLionel Sambuc }
618*433d6423SLionel Sambuc 
619*433d6423SLionel Sambuc /* Decode two lower case hex digits into an 8 bit byte value */
zgethex()620*433d6423SLionel Sambuc int zgethex()
621*433d6423SLionel Sambuc {
622*433d6423SLionel Sambuc 	register int c;
623*433d6423SLionel Sambuc 
624*433d6423SLionel Sambuc 	c = zgeth1();
625*433d6423SLionel Sambuc 	if (Verbose>8)
626*433d6423SLionel Sambuc 		vfile("zgethex: %02X", c);
627*433d6423SLionel Sambuc 	return c;
628*433d6423SLionel Sambuc }
zgeth1()629*433d6423SLionel Sambuc int zgeth1()
630*433d6423SLionel Sambuc {
631*433d6423SLionel Sambuc 	register int c, n;
632*433d6423SLionel Sambuc 
633*433d6423SLionel Sambuc 	if ((c = noxrd7()) < 0)
634*433d6423SLionel Sambuc 		return c;
635*433d6423SLionel Sambuc 	n = c - '0';
636*433d6423SLionel Sambuc 	if (n > 9)
637*433d6423SLionel Sambuc 		n -= ('a' - ':');
638*433d6423SLionel Sambuc 	if (n & ~0xF)
639*433d6423SLionel Sambuc 		return ERROR;
640*433d6423SLionel Sambuc 	if ((c = noxrd7()) < 0)
641*433d6423SLionel Sambuc 		return c;
642*433d6423SLionel Sambuc 	c -= '0';
643*433d6423SLionel Sambuc 	if (c > 9)
644*433d6423SLionel Sambuc 		c -= ('a' - ':');
645*433d6423SLionel Sambuc 	if (c & ~0xF)
646*433d6423SLionel Sambuc 		return ERROR;
647*433d6423SLionel Sambuc 	c += (n<<4);
648*433d6423SLionel Sambuc 	return c;
649*433d6423SLionel Sambuc }
650*433d6423SLionel Sambuc 
651*433d6423SLionel Sambuc /*
652*433d6423SLionel Sambuc  * Read a byte, checking for ZMODEM escape encoding
653*433d6423SLionel Sambuc  *  including CAN*5 which represents a quick abort
654*433d6423SLionel Sambuc  */
zdlread()655*433d6423SLionel Sambuc int zdlread()
656*433d6423SLionel Sambuc {
657*433d6423SLionel Sambuc 	register int c;
658*433d6423SLionel Sambuc 
659*433d6423SLionel Sambuc again:
660*433d6423SLionel Sambuc 	/* Quick check for non control characters */
661*433d6423SLionel Sambuc 	if ((c = readline(Rxtimeout)) & 0140)
662*433d6423SLionel Sambuc 		return c;
663*433d6423SLionel Sambuc 	switch (c) {
664*433d6423SLionel Sambuc 	case ZDLE:
665*433d6423SLionel Sambuc 		break;
666*433d6423SLionel Sambuc 	case 023:
667*433d6423SLionel Sambuc 	case 0223:
668*433d6423SLionel Sambuc 	case 021:
669*433d6423SLionel Sambuc 	case 0221:
670*433d6423SLionel Sambuc 		goto again;
671*433d6423SLionel Sambuc 	default:
672*433d6423SLionel Sambuc 		if (Zctlesc && !(c & 0140)) {
673*433d6423SLionel Sambuc 			goto again;
674*433d6423SLionel Sambuc 		}
675*433d6423SLionel Sambuc 		return c;
676*433d6423SLionel Sambuc 	}
677*433d6423SLionel Sambuc again2:
678*433d6423SLionel Sambuc 	if ((c = readline(Rxtimeout)) < 0)
679*433d6423SLionel Sambuc 		return c;
680*433d6423SLionel Sambuc 	if (c == CAN && (c = readline(Rxtimeout)) < 0)
681*433d6423SLionel Sambuc 		return c;
682*433d6423SLionel Sambuc 	if (c == CAN && (c = readline(Rxtimeout)) < 0)
683*433d6423SLionel Sambuc 		return c;
684*433d6423SLionel Sambuc 	if (c == CAN && (c = readline(Rxtimeout)) < 0)
685*433d6423SLionel Sambuc 		return c;
686*433d6423SLionel Sambuc 	switch (c) {
687*433d6423SLionel Sambuc 	case CAN:
688*433d6423SLionel Sambuc 		return GOTCAN;
689*433d6423SLionel Sambuc 	case ZCRCE:
690*433d6423SLionel Sambuc 	case ZCRCG:
691*433d6423SLionel Sambuc 	case ZCRCQ:
692*433d6423SLionel Sambuc 	case ZCRCW:
693*433d6423SLionel Sambuc 		return (c | GOTOR);
694*433d6423SLionel Sambuc 	case ZRUB0:
695*433d6423SLionel Sambuc 		return 0177;
696*433d6423SLionel Sambuc 	case ZRUB1:
697*433d6423SLionel Sambuc 		return 0377;
698*433d6423SLionel Sambuc 	case 023:
699*433d6423SLionel Sambuc 	case 0223:
700*433d6423SLionel Sambuc 	case 021:
701*433d6423SLionel Sambuc 	case 0221:
702*433d6423SLionel Sambuc 		goto again2;
703*433d6423SLionel Sambuc 	default:
704*433d6423SLionel Sambuc 		if (Zctlesc && ! (c & 0140)) {
705*433d6423SLionel Sambuc 			goto again2;
706*433d6423SLionel Sambuc 		}
707*433d6423SLionel Sambuc 		if ((c & 0140) ==  0100)
708*433d6423SLionel Sambuc 			return (c ^ 0100);
709*433d6423SLionel Sambuc 		break;
710*433d6423SLionel Sambuc 	}
711*433d6423SLionel Sambuc 	if (Verbose>1)
712*433d6423SLionel Sambuc 		zperr("Bad escape sequence %x", c);
713*433d6423SLionel Sambuc 	return ERROR;
714*433d6423SLionel Sambuc }
715*433d6423SLionel Sambuc 
716*433d6423SLionel Sambuc /*
717*433d6423SLionel Sambuc  * Read a character from the modem line with timeout.
718*433d6423SLionel Sambuc  *  Eat parity, XON and XOFF characters.
719*433d6423SLionel Sambuc  */
noxrd7()720*433d6423SLionel Sambuc int noxrd7()
721*433d6423SLionel Sambuc {
722*433d6423SLionel Sambuc 	register int c;
723*433d6423SLionel Sambuc 
724*433d6423SLionel Sambuc 	for (;;) {
725*433d6423SLionel Sambuc 		if ((c = readline(Rxtimeout)) < 0)
726*433d6423SLionel Sambuc 			return c;
727*433d6423SLionel Sambuc 		switch (c &= 0177) {
728*433d6423SLionel Sambuc 		case XON:
729*433d6423SLionel Sambuc 		case XOFF:
730*433d6423SLionel Sambuc 			continue;
731*433d6423SLionel Sambuc 		default:
732*433d6423SLionel Sambuc 			if (Zctlesc && !(c & 0140))
733*433d6423SLionel Sambuc 				continue;
734*433d6423SLionel Sambuc 		case '\r':
735*433d6423SLionel Sambuc 		case '\n':
736*433d6423SLionel Sambuc 		case ZDLE:
737*433d6423SLionel Sambuc 			return c;
738*433d6423SLionel Sambuc 		}
739*433d6423SLionel Sambuc 	}
740*433d6423SLionel Sambuc }
741*433d6423SLionel Sambuc 
742*433d6423SLionel Sambuc /* Store long integer pos in Txhdr */
stohdr(long pos)743*433d6423SLionel Sambuc void stohdr(long pos)
744*433d6423SLionel Sambuc {
745*433d6423SLionel Sambuc 	Txhdr[ZP0] = pos;
746*433d6423SLionel Sambuc 	Txhdr[ZP1] = pos>>8;
747*433d6423SLionel Sambuc 	Txhdr[ZP2] = pos>>16;
748*433d6423SLionel Sambuc 	Txhdr[ZP3] = pos>>24;
749*433d6423SLionel Sambuc }
750*433d6423SLionel Sambuc 
751*433d6423SLionel Sambuc /* Recover a long integer from a header */
752*433d6423SLionel Sambuc long
rclhdr(char * hdr)753*433d6423SLionel Sambuc rclhdr(char *hdr)
754*433d6423SLionel Sambuc {
755*433d6423SLionel Sambuc 	register long l;
756*433d6423SLionel Sambuc 
757*433d6423SLionel Sambuc 	l = (hdr[ZP3] & 0377);
758*433d6423SLionel Sambuc 	l = (l << 8) | (hdr[ZP2] & 0377);
759*433d6423SLionel Sambuc 	l = (l << 8) | (hdr[ZP1] & 0377);
760*433d6423SLionel Sambuc 	l = (l << 8) | (hdr[ZP0] & 0377);
761*433d6423SLionel Sambuc 	return l;
762*433d6423SLionel Sambuc }
763*433d6423SLionel Sambuc 
764*433d6423SLionel Sambuc /* End of zm.c */
765