xref: /csrg-svn/usr.bin/uucp/uucico/fio.c (revision 23599)
1*23599Sbloom #ifndef lint
2*23599Sbloom static char sccsid[] = "@(#)fio.c	5.1 (Berkeley) 06/19/85";
3*23599Sbloom #endif
4*23599Sbloom 
5*23599Sbloom /*
6*23599Sbloom  * flow control protocol.
7*23599Sbloom  *
8*23599Sbloom  * This protocol relies on flow control of the data stream.
9*23599Sbloom  * It is meant for working over links that can (almost) be
10*23599Sbloom  * guaranteed to be errorfree, specifically X.25/PAD links.
11*23599Sbloom  * A sumcheck is carried out over a whole file only. If a
12*23599Sbloom  * transport fails the receiver can request retransmission(s).
13*23599Sbloom  * This protocol uses a 7-bit datapath only, so it can be
14*23599Sbloom  * used on links that are not 8-bit transparent.
15*23599Sbloom  *
16*23599Sbloom  * When using this protocol with an X.25 PAD:
17*23599Sbloom  * Although this protocol uses no control chars except CR,
18*23599Sbloom  * control chars NULL and ^P are used before this protocol
19*23599Sbloom  * is started; since ^P is the default char for accessing
20*23599Sbloom  * PAD X.28 command mode, be sure to disable that access
21*23599Sbloom  * (PAD par 1). Also make sure both flow control pars
22*23599Sbloom  * (5 and 12) are set. The CR used in this proto is meant
23*23599Sbloom  * to trigger packet transmission, hence par 3 should be
24*23599Sbloom  * set to 2; a good value for the Idle Timer (par 4) is 10.
25*23599Sbloom  * All other pars should be set to 0.
26*23599Sbloom  * Normally a calling site will take care of setting the
27*23599Sbloom  * local PAD pars via an X.28 command and those of the remote
28*23599Sbloom  * PAD via an X.29 command, unless the remote site has a
29*23599Sbloom  * special channel assigned for this protocol with the proper
30*23599Sbloom  * par settings.
31*23599Sbloom  *
32*23599Sbloom  * Author: Piet Beertema, CWI, Amsterdam, Sep 1984
33*23599Sbloom  */
34*23599Sbloom 
35*23599Sbloom #include <signal.h>
36*23599Sbloom #include "uucp.h"
37*23599Sbloom #ifdef USG
38*23599Sbloom #include <termio.h>
39*23599Sbloom #else !USG
40*23599Sbloom #include <sgtty.h>
41*23599Sbloom #endif !USG
42*23599Sbloom #include <setjmp.h>
43*23599Sbloom 
44*23599Sbloom #define FBUFSIZ		256
45*23599Sbloom 
46*23599Sbloom #ifndef MAXMSGLEN
47*23599Sbloom #define MAXMSGLEN	BUFSIZ
48*23599Sbloom #endif MAXMSGLEN
49*23599Sbloom 
50*23599Sbloom static int fchksum;
51*23599Sbloom static jmp_buf Ffailbuf;
52*23599Sbloom 
53*23599Sbloom static
54*23599Sbloom falarm()
55*23599Sbloom {
56*23599Sbloom 	signal(SIGALRM, falarm);
57*23599Sbloom 	longjmp(Ffailbuf, 1);
58*23599Sbloom }
59*23599Sbloom 
60*23599Sbloom static int (*fsig)();
61*23599Sbloom 
62*23599Sbloom #ifndef USG
63*23599Sbloom #define TCGETA	TIOCGETP
64*23599Sbloom #define TCSETA	TIOCSETP
65*23599Sbloom #define termio	sgttyb
66*23599Sbloom #endif USG
67*23599Sbloom 
68*23599Sbloom fturnon()
69*23599Sbloom {
70*23599Sbloom 	int ret;
71*23599Sbloom 	struct termio ttbuf;
72*23599Sbloom 
73*23599Sbloom 	ioctl(Ifn, TCGETA, &ttbuf);
74*23599Sbloom #ifdef USG
75*23599Sbloom 	ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
76*23599Sbloom 	ttbuf.c_cc[VMIN] = FBUFSIZ > 64 ? 64 : FBUFSIZ;
77*23599Sbloom 	ttbuf.c_cc[VTIME] = 5;
78*23599Sbloom #else
79*23599Sbloom 	ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
80*23599Sbloom #endif USG
81*23599Sbloom 	ret = ioctl(Ifn, TCSETA, &ttbuf);
82*23599Sbloom 	ASSERT(ret >= 0, "STTY FAILED", "", ret);
83*23599Sbloom 	fsig = signal(SIGALRM, falarm);
84*23599Sbloom 	/* give the other side time to perform its ioctl;
85*23599Sbloom 	 * otherwise it may flush out the first data this
86*23599Sbloom 	 * side is about to send.
87*23599Sbloom 	 */
88*23599Sbloom 	sleep(2);
89*23599Sbloom 	return SUCCESS;
90*23599Sbloom }
91*23599Sbloom 
92*23599Sbloom fturnoff()
93*23599Sbloom {
94*23599Sbloom 	(void) signal(SIGALRM, fsig);
95*23599Sbloom 	return SUCCESS;
96*23599Sbloom }
97*23599Sbloom 
98*23599Sbloom fwrmsg(type, str, fn)
99*23599Sbloom register char *str;
100*23599Sbloom int fn;
101*23599Sbloom char type;
102*23599Sbloom {
103*23599Sbloom 	register char *s;
104*23599Sbloom 	char bufr[MAXMSGLEN];
105*23599Sbloom 
106*23599Sbloom 	s = bufr;
107*23599Sbloom 	*s++ = type;
108*23599Sbloom 	while (*str)
109*23599Sbloom 		*s++ = *str++;
110*23599Sbloom 	if (*(s-1) == '\n')
111*23599Sbloom 		s--;
112*23599Sbloom 	*s++ = '\r';
113*23599Sbloom 	(void) write(fn, bufr, s - bufr);
114*23599Sbloom 	return SUCCESS;
115*23599Sbloom }
116*23599Sbloom 
117*23599Sbloom frdmsg(str, fn)
118*23599Sbloom register char *str;
119*23599Sbloom register int fn;
120*23599Sbloom {
121*23599Sbloom 	register char *smax;
122*23599Sbloom 
123*23599Sbloom 	if (setjmp(Ffailbuf))
124*23599Sbloom 		return FAIL;
125*23599Sbloom 	smax = str + MAXMSGLEN - 1;
126*23599Sbloom 	(void) alarm(2*MAXMSGTIME);
127*23599Sbloom 	for (;;) {
128*23599Sbloom 		if (read(fn, str, 1) <= 0)
129*23599Sbloom 			goto msgerr;
130*23599Sbloom 		if (*str == '\r')
131*23599Sbloom 			break;
132*23599Sbloom 		if (*str < ' ')
133*23599Sbloom 			continue;
134*23599Sbloom 		if (str++ >= smax)
135*23599Sbloom 			goto msgerr;
136*23599Sbloom 	}
137*23599Sbloom 	*str = '\0';
138*23599Sbloom 	(void) alarm(0);
139*23599Sbloom 	return SUCCESS;
140*23599Sbloom msgerr:
141*23599Sbloom 	(void) alarm(0);
142*23599Sbloom 	return FAIL;
143*23599Sbloom }
144*23599Sbloom 
145*23599Sbloom fwrdata(fp1, fn)
146*23599Sbloom FILE *fp1;
147*23599Sbloom int fn;
148*23599Sbloom {
149*23599Sbloom 	register int flen, alen, ret;
150*23599Sbloom 	char ibuf[FBUFSIZ];
151*23599Sbloom 	char ack;
152*23599Sbloom 	long abytes, fbytes;
153*23599Sbloom 	struct timeb t1, t2;
154*23599Sbloom 	int mil, retries = 0;
155*23599Sbloom 
156*23599Sbloom 	ret = FAIL;
157*23599Sbloom retry:
158*23599Sbloom 	fchksum = 0xffff;
159*23599Sbloom 	abytes = fbytes = 0L;
160*23599Sbloom 	ack = '\0';
161*23599Sbloom #ifdef USG
162*23599Sbloom 	time(&t1.time);
163*23599Sbloom 	t1.millitm = 0;
164*23599Sbloom #else !USG
165*23599Sbloom 	ftime(&t1);
166*23599Sbloom #endif !USG
167*23599Sbloom 	while ((flen = fread(ibuf, sizeof (char), FBUFSIZ, fp1)) > 0) {
168*23599Sbloom 		alen = fwrblk(fn, ibuf, flen);
169*23599Sbloom 		abytes += alen >= 0 ? alen : -alen;
170*23599Sbloom 		if (alen <= 0)
171*23599Sbloom 			goto acct;
172*23599Sbloom 		fbytes += flen;
173*23599Sbloom 	}
174*23599Sbloom 	sprintf(ibuf, "\176\176%04x\r", fchksum);
175*23599Sbloom 	abytes += alen = strlen(ibuf);
176*23599Sbloom 	if (write(fn, ibuf, alen) == alen) {
177*23599Sbloom 		DEBUG(8, "%d\n", alen);
178*23599Sbloom 		DEBUG(8, "checksum: %04x\n", fchksum);
179*23599Sbloom 		if (frdmsg(ibuf, fn) != FAIL) {
180*23599Sbloom 			if ((ack = ibuf[0]) == 'G')
181*23599Sbloom 				ret = 0;
182*23599Sbloom 			DEBUG(4, "ack - '%c'\n", ack);
183*23599Sbloom 		}
184*23599Sbloom 	}
185*23599Sbloom acct:
186*23599Sbloom 	if (ack == 'R') {
187*23599Sbloom 		DEBUG(4, "RETRY:\n", 0);
188*23599Sbloom 		fseek(fp1, 0L, 0);
189*23599Sbloom 		retries++;
190*23599Sbloom 		goto retry;
191*23599Sbloom 	}
192*23599Sbloom #ifdef USG
193*23599Sbloom 	time(&t2.time);
194*23599Sbloom 	t2.millitm = 0;
195*23599Sbloom #else !USG
196*23599Sbloom 	ftime(&t2);
197*23599Sbloom #endif !USG
198*23599Sbloom 	Now = t2;
199*23599Sbloom 	t2.time -= t1.time;
200*23599Sbloom 	mil = t2.millitm - t1.millitm;
201*23599Sbloom 	if (mil < 0) {
202*23599Sbloom 		--t2.time;
203*23599Sbloom 		mil += 1000;
204*23599Sbloom 	}
205*23599Sbloom 	sprintf(ibuf, "sent data %ld bytes %ld.%02d secs",
206*23599Sbloom 				fbytes, (long)t2.time, mil/10);
207*23599Sbloom 	sysacct(abytes, t2.time - t1.time);
208*23599Sbloom 	if (retries > 0)
209*23599Sbloom 		sprintf((char *)ibuf+strlen(ibuf)," %d retries", retries);
210*23599Sbloom 	DEBUG(1, "%s\n", ibuf);
211*23599Sbloom 	syslog(ibuf);
212*23599Sbloom #ifdef SYSACCT
213*23599Sbloom 	if (ret)
214*23599Sbloom 		sysaccf(NULL);		/* force accounting */
215*23599Sbloom #endif SYSACCT
216*23599Sbloom 	return ret;
217*23599Sbloom }
218*23599Sbloom 
219*23599Sbloom /* max. attempts to retransmit a file: */
220*23599Sbloom #define MAXRETRIES	(fbytes < 10000L ? 2 : 1)
221*23599Sbloom 
222*23599Sbloom frddata(fn, fp2)
223*23599Sbloom register int fn;
224*23599Sbloom register FILE *fp2;
225*23599Sbloom {
226*23599Sbloom 	register int flen;
227*23599Sbloom 	register char eof;
228*23599Sbloom 	char ibuf[FBUFSIZ];
229*23599Sbloom 	int ret, retries = 0;
230*23599Sbloom 	long alen, abytes, fbytes;
231*23599Sbloom 	struct timeb t1, t2;
232*23599Sbloom 	int mil;
233*23599Sbloom 
234*23599Sbloom 	ret = FAIL;
235*23599Sbloom retry:
236*23599Sbloom 	fchksum = 0xffff;
237*23599Sbloom 	abytes = fbytes = 0L;
238*23599Sbloom #ifdef USG
239*23599Sbloom 	time(&t1.time);
240*23599Sbloom 	t1.millitm = 0;
241*23599Sbloom #else !USG
242*23599Sbloom 	ftime(&t1);
243*23599Sbloom #endif !USG
244*23599Sbloom 	do {
245*23599Sbloom 		flen = frdblk(ibuf, fn, &alen);
246*23599Sbloom 		abytes += alen;
247*23599Sbloom 		if (flen < 0)
248*23599Sbloom 			goto acct;
249*23599Sbloom 		if (eof = flen > FBUFSIZ)
250*23599Sbloom 			flen -= FBUFSIZ + 1;
251*23599Sbloom 		fbytes += flen;
252*23599Sbloom 		if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
253*23599Sbloom 			goto acct;
254*23599Sbloom 	} while (!eof);
255*23599Sbloom 	ret = 0;
256*23599Sbloom acct:
257*23599Sbloom 	if (ret) {
258*23599Sbloom 		if (retries++ < MAXRETRIES) {
259*23599Sbloom 			DEBUG(8, "send ack: 'R'\n", 0);
260*23599Sbloom 			fwrmsg('R', "", fn);
261*23599Sbloom 			fseek(fp2, 0L, 0);
262*23599Sbloom 			DEBUG(4, "RETRY:\n", 0);
263*23599Sbloom 			goto retry;
264*23599Sbloom 		}
265*23599Sbloom 		DEBUG(8, "send ack: 'Q'\n", 0);
266*23599Sbloom 		fwrmsg('Q', "", fn);
267*23599Sbloom #ifdef SYSACCT
268*23599Sbloom 		sysaccf(NULL);		/* force accounting */
269*23599Sbloom #endif SYSACCT
270*23599Sbloom 	} else {
271*23599Sbloom 		DEBUG(8, "send ack: 'G'\n", 0);
272*23599Sbloom 		fwrmsg('G', "", fn);
273*23599Sbloom 	}
274*23599Sbloom #ifdef USG
275*23599Sbloom 	time(&t2.time);
276*23599Sbloom 	t2.millitm = 0;
277*23599Sbloom #else !USG
278*23599Sbloom 	ftime(&t2);
279*23599Sbloom #endif !USG
280*23599Sbloom 	Now = t2;
281*23599Sbloom 	t2.time -= t1.time;
282*23599Sbloom 	mil = t2.millitm - t1.millitm;
283*23599Sbloom 	if (mil < 0) {
284*23599Sbloom 		--t2.time;
285*23599Sbloom 		mil += 1000;
286*23599Sbloom 	}
287*23599Sbloom 	sprintf(ibuf, "received data %ld bytes %ld.%02d secs",
288*23599Sbloom 				fbytes, (long)t2.time, mil/10);
289*23599Sbloom 	sysacct(abytes, t2.time - t1.time);
290*23599Sbloom 	if (retries > 0)
291*23599Sbloom 		sprintf((char *)ibuf+strlen(ibuf)," %d retries", retries);
292*23599Sbloom 	DEBUG(1, "%s\n", ibuf);
293*23599Sbloom 	syslog(ibuf);
294*23599Sbloom 	return ret;
295*23599Sbloom }
296*23599Sbloom 
297*23599Sbloom static
298*23599Sbloom frdbuf(blk, len, fn)
299*23599Sbloom register char *blk;
300*23599Sbloom register int len;
301*23599Sbloom register int fn;
302*23599Sbloom {
303*23599Sbloom 	static int ret = FBUFSIZ / 2;
304*23599Sbloom #ifndef Not080
305*23599Sbloom 	extern int linebaudrate;
306*23599Sbloom #endif Not080
307*23599Sbloom 
308*23599Sbloom 	if (setjmp(Ffailbuf))
309*23599Sbloom 		return FAIL;
310*23599Sbloom #ifndef Not080
311*23599Sbloom 	if (len == FBUFSIZ && ret < FBUFSIZ / 2 &&
312*23599Sbloom 	    linebaudrate > 0 && linebaudrate < 4800)
313*23599Sbloom 		sleep(1);
314*23599Sbloom #endif Not080
315*23599Sbloom 	(void) alarm(MAXMSGTIME);
316*23599Sbloom 	ret = read(fn, blk, len);
317*23599Sbloom 	alarm(0);
318*23599Sbloom 	return ret <= 0 ? FAIL : ret;
319*23599Sbloom }
320*23599Sbloom 
321*23599Sbloom /* call ultouch every TC calls to either frdblk or fwrblk  */
322*23599Sbloom 
323*23599Sbloom #define	TC	20
324*23599Sbloom static	int tc = TC;
325*23599Sbloom 
326*23599Sbloom /* Byte conversion:
327*23599Sbloom  *
328*23599Sbloom  *   from        pre       to
329*23599Sbloom  * 000-037       172     100-137
330*23599Sbloom  * 040-171               040-171
331*23599Sbloom  * 172-177       173     072-077
332*23599Sbloom  * 200-237       174     100-137
333*23599Sbloom  * 240-371       175     040-171
334*23599Sbloom  * 372-377       176     072-077
335*23599Sbloom  */
336*23599Sbloom 
337*23599Sbloom static
338*23599Sbloom fwrblk(fn, ip, len)
339*23599Sbloom int fn;
340*23599Sbloom register char *ip;
341*23599Sbloom register int len;
342*23599Sbloom {
343*23599Sbloom 	register char *op;
344*23599Sbloom 	register int sum, nl;
345*23599Sbloom 	int ret;
346*23599Sbloom 	char obuf[FBUFSIZ * 2];
347*23599Sbloom 
348*23599Sbloom 	/* call ultouch occasionally */
349*23599Sbloom 	if (--tc < 0) {
350*23599Sbloom 		tc = TC;
351*23599Sbloom 		ultouch();
352*23599Sbloom 	}
353*23599Sbloom 	DEBUG(8, "%d/", len);
354*23599Sbloom 	op = obuf;
355*23599Sbloom 	nl = 0;
356*23599Sbloom 	sum = fchksum;
357*23599Sbloom 	do {
358*23599Sbloom 		if (sum & 0x8000) {
359*23599Sbloom 			sum <<= 1;
360*23599Sbloom 			sum++;
361*23599Sbloom 		} else
362*23599Sbloom 			sum <<= 1;
363*23599Sbloom 		sum += *ip & 0377;
364*23599Sbloom 		sum &= 0xffff;
365*23599Sbloom 		if (*ip & 0200) {
366*23599Sbloom 			*ip &= 0177;
367*23599Sbloom 			if (*ip < 040) {
368*23599Sbloom 				*op++ = '\174';
369*23599Sbloom 				*op++ = *ip++ + 0100;
370*23599Sbloom 			} else
371*23599Sbloom 			if (*ip <= 0171) {
372*23599Sbloom 				*op++ = '\175';
373*23599Sbloom 				*op++ = *ip++;
374*23599Sbloom 			}
375*23599Sbloom 			else {
376*23599Sbloom 				*op++ = '\176';
377*23599Sbloom 				*op++ = *ip++ - 0100;
378*23599Sbloom 			}
379*23599Sbloom 			nl += 2;
380*23599Sbloom 		} else {
381*23599Sbloom 			if (*ip < 040) {
382*23599Sbloom 				*op++ = '\172';
383*23599Sbloom 				*op++ = *ip++ + 0100;
384*23599Sbloom 				nl += 2;
385*23599Sbloom 			} else
386*23599Sbloom 			if (*ip <= 0171) {
387*23599Sbloom 				*op++ = *ip++;
388*23599Sbloom 				nl++;
389*23599Sbloom 			} else {
390*23599Sbloom 				*op++ = '\173';
391*23599Sbloom 				*op++ = *ip++ - 0100;
392*23599Sbloom 				nl += 2;
393*23599Sbloom 			}
394*23599Sbloom 		}
395*23599Sbloom 	} while (--len);
396*23599Sbloom 	fchksum = sum;
397*23599Sbloom 	DEBUG(8, "%d,", nl);
398*23599Sbloom 	ret = write(fn, obuf, nl);
399*23599Sbloom 	return ret == nl ? nl : ret < 0 ? 0 : -ret;
400*23599Sbloom }
401*23599Sbloom 
402*23599Sbloom static
403*23599Sbloom frdblk(ip, fn, rlen)
404*23599Sbloom register char *ip;
405*23599Sbloom int fn;
406*23599Sbloom long *rlen;
407*23599Sbloom {
408*23599Sbloom 	register char *op, c;
409*23599Sbloom 	register int sum, len, nl;
410*23599Sbloom 	char buf[5], *erbp = ip;
411*23599Sbloom 	int i;
412*23599Sbloom 	static char special = 0;
413*23599Sbloom 
414*23599Sbloom 	/* call ultouch occasionally */
415*23599Sbloom 	if (--tc < 0) {
416*23599Sbloom 		tc = TC;
417*23599Sbloom 		ultouch();
418*23599Sbloom 	}
419*23599Sbloom 
420*23599Sbloom 	if ((len = frdbuf(ip, FBUFSIZ, fn)) == FAIL) {
421*23599Sbloom 		*rlen = 0;
422*23599Sbloom 		goto dcorr;
423*23599Sbloom 	}
424*23599Sbloom 	*rlen = len;
425*23599Sbloom 	DEBUG(8, "%d/", len);
426*23599Sbloom 	op = ip;
427*23599Sbloom 	nl = 0;
428*23599Sbloom 	sum = fchksum;
429*23599Sbloom 	do {
430*23599Sbloom 		if ((*ip &= 0177) >= '\172') {
431*23599Sbloom 			if (special) {
432*23599Sbloom 				DEBUG(8, "%d", nl);
433*23599Sbloom 				special = 0;
434*23599Sbloom 				op = buf;
435*23599Sbloom 				if (*ip++ != '\176' || (i = --len) > 5)
436*23599Sbloom 					goto dcorr;
437*23599Sbloom 				while (i--)
438*23599Sbloom 					*op++ = *ip++;
439*23599Sbloom 				while (len < 5) {
440*23599Sbloom 					i = frdbuf(&buf[len], 5 - len, fn);
441*23599Sbloom 					if (i == FAIL) {
442*23599Sbloom 						len = FAIL;
443*23599Sbloom 						goto dcorr;
444*23599Sbloom 					}
445*23599Sbloom 					DEBUG(8, ",%d", i);
446*23599Sbloom 					len += i;
447*23599Sbloom 					*rlen += i;
448*23599Sbloom 				}
449*23599Sbloom 				if (buf[4] != '\r')
450*23599Sbloom 					goto dcorr;
451*23599Sbloom 				sscanf(buf, "%4x", &fchksum);
452*23599Sbloom 				DEBUG(8, "\nchecksum: %04x\n", sum);
453*23599Sbloom 				if (fchksum == sum)
454*23599Sbloom 					return FBUFSIZ + 1 + nl;
455*23599Sbloom 				else {
456*23599Sbloom 					DEBUG(8, "\n", 0);
457*23599Sbloom 					DEBUG(4, "Bad checksum\n", 0);
458*23599Sbloom 					return FAIL;
459*23599Sbloom 				}
460*23599Sbloom 			}
461*23599Sbloom 			special = *ip++;
462*23599Sbloom 		} else {
463*23599Sbloom 			if (*ip < '\040') {
464*23599Sbloom 				/* error: shouldn't get control chars */
465*23599Sbloom 				goto dcorr;
466*23599Sbloom 			}
467*23599Sbloom 			switch (special) {
468*23599Sbloom 			case 0:
469*23599Sbloom 				c = *ip++;
470*23599Sbloom 				break;
471*23599Sbloom 			case '\172':
472*23599Sbloom 				c = *ip++ - 0100;
473*23599Sbloom 				break;
474*23599Sbloom 			case '\173':
475*23599Sbloom 				c = *ip++ + 0100;
476*23599Sbloom 				break;
477*23599Sbloom 			case '\174':
478*23599Sbloom 				c = *ip++ + 0100;
479*23599Sbloom 				break;
480*23599Sbloom 			case '\175':
481*23599Sbloom 				c = *ip++ + 0200;
482*23599Sbloom 				break;
483*23599Sbloom 			case '\176':
484*23599Sbloom 				c = *ip++ + 0300;
485*23599Sbloom 				break;
486*23599Sbloom 			}
487*23599Sbloom 			*op++ = c;
488*23599Sbloom 			if (sum & 0x8000) {
489*23599Sbloom 				sum <<= 1;
490*23599Sbloom 				sum++;
491*23599Sbloom 			} else
492*23599Sbloom 				sum <<= 1;
493*23599Sbloom 			sum += c & 0377;
494*23599Sbloom 			sum &= 0xffff;
495*23599Sbloom 			special = 0;
496*23599Sbloom 			nl++;
497*23599Sbloom 		}
498*23599Sbloom 	} while (--len);
499*23599Sbloom 	fchksum = sum;
500*23599Sbloom 	DEBUG(8, "%d,", nl);
501*23599Sbloom 	return nl;
502*23599Sbloom dcorr:
503*23599Sbloom 	DEBUG(8, "\n", 0);
504*23599Sbloom 	DEBUG(4, "Data corrupted\n", 0);
505*23599Sbloom 	while (len != FAIL) {
506*23599Sbloom 		if ((len = frdbuf(erbp, FBUFSIZ, fn)) != FAIL)
507*23599Sbloom 			*rlen += len;
508*23599Sbloom 	}
509*23599Sbloom 	return FAIL;
510*23599Sbloom }
511