xref: /csrg-svn/usr.bin/uucp/uucico/fio.c (revision 33563)
123599Sbloom #ifndef lint
2*33563Srick static char sccsid[] = "@(#)fio.c	5.4 (Berkeley) 02/24/88";
323599Sbloom #endif
423599Sbloom 
523599Sbloom /*
623599Sbloom  * flow control protocol.
723599Sbloom  *
823599Sbloom  * This protocol relies on flow control of the data stream.
923599Sbloom  * It is meant for working over links that can (almost) be
1023599Sbloom  * guaranteed to be errorfree, specifically X.25/PAD links.
1123599Sbloom  * A sumcheck is carried out over a whole file only. If a
1223599Sbloom  * transport fails the receiver can request retransmission(s).
1323599Sbloom  * This protocol uses a 7-bit datapath only, so it can be
1423599Sbloom  * used on links that are not 8-bit transparent.
1523599Sbloom  *
1623599Sbloom  * When using this protocol with an X.25 PAD:
1723599Sbloom  * Although this protocol uses no control chars except CR,
1823599Sbloom  * control chars NULL and ^P are used before this protocol
1923599Sbloom  * is started; since ^P is the default char for accessing
2023599Sbloom  * PAD X.28 command mode, be sure to disable that access
2123599Sbloom  * (PAD par 1). Also make sure both flow control pars
2223599Sbloom  * (5 and 12) are set. The CR used in this proto is meant
2323599Sbloom  * to trigger packet transmission, hence par 3 should be
2423599Sbloom  * set to 2; a good value for the Idle Timer (par 4) is 10.
2523599Sbloom  * All other pars should be set to 0.
2625130Sbloom  *
2723599Sbloom  * Normally a calling site will take care of setting the
2823599Sbloom  * local PAD pars via an X.28 command and those of the remote
2923599Sbloom  * PAD via an X.29 command, unless the remote site has a
3023599Sbloom  * special channel assigned for this protocol with the proper
3123599Sbloom  * par settings.
3223599Sbloom  *
3325130Sbloom  * Additional comments for hosts with direct X.25 access:
3425130Sbloom  * - the global variable IsTcpIp, when set, excludes the ioctl's,
3525130Sbloom  *   so the same binary can run on X.25 and non-X.25 hosts;
3625130Sbloom  * - reads are done in small chunks, which can be smaller than
3725130Sbloom  *   the packet size; your X.25 driver must support that.
3825130Sbloom  *
3925130Sbloom  *
4025130Sbloom  * Author:
4125130Sbloom  *	Piet Beertema, CWI, Amsterdam, Sep 1984
4225130Sbloom  * Modified for X.25 hosts:
4325130Sbloom  *	Robert Elz, Melbourne Univ, Mar 1985
4423599Sbloom  */
4523599Sbloom 
4625130Sbloom #include "uucp.h"
4723599Sbloom #include <signal.h>
4823599Sbloom #ifdef USG
4923599Sbloom #include <termio.h>
5023599Sbloom #else !USG
5123599Sbloom #include <sgtty.h>
5223599Sbloom #endif !USG
5323599Sbloom #include <setjmp.h>
5423599Sbloom 
55*33563Srick #define FIBUFSIZ	4096	/* for X.25 interfaces: set equal to packet size,
5625130Sbloom 				 * but see comment above
5725130Sbloom 				 */
5823599Sbloom 
59*33563Srick #define FOBUFSIZ	4096	/* for X.25 interfaces: set equal to packet size;
6025130Sbloom 				 * otherwise make as large as feasible to reduce
6125130Sbloom 				 * number of write system calls
6225130Sbloom 				 */
6325130Sbloom 
6423599Sbloom #ifndef MAXMSGLEN
6523599Sbloom #define MAXMSGLEN	BUFSIZ
6623599Sbloom #endif MAXMSGLEN
6723599Sbloom 
6823599Sbloom static int fchksum;
6923599Sbloom static jmp_buf Ffailbuf;
7023599Sbloom 
71*33563Srick extern long Bytes_Sent, Bytes_Received;
72*33563Srick 
7323599Sbloom static
7423599Sbloom falarm()
7523599Sbloom {
7623599Sbloom 	signal(SIGALRM, falarm);
7723599Sbloom 	longjmp(Ffailbuf, 1);
7823599Sbloom }
7923599Sbloom 
8023599Sbloom static int (*fsig)();
8123599Sbloom 
8223599Sbloom #ifndef USG
8323599Sbloom #define TCGETA	TIOCGETP
8423599Sbloom #define TCSETA	TIOCSETP
8523599Sbloom #define termio	sgttyb
8623599Sbloom #endif USG
87*33563Srick static struct	termio ttbuf;
8823599Sbloom 
8923599Sbloom fturnon()
9023599Sbloom {
9123599Sbloom 	int ret;
92*33563Srick 	int ttbuf_flags;
9323599Sbloom 
9425130Sbloom 	if (!IsTcpIp) {
9525130Sbloom 		ioctl(Ifn, TCGETA, &ttbuf);
9623599Sbloom #ifdef USG
97*33563Srick 		ttbuf_flags = ttbuf.c_iflag;
9825130Sbloom 		ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
9925130Sbloom 		ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ;
10025130Sbloom 		ttbuf.c_cc[VTIME] = 5;
101*33563Srick 		ret = ioctl(Ifn, TCSETA, &ttbuf);
102*33563Srick 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
103*33563Srick 		ttbuf.c_iflag = ttbuf_flags;
10425130Sbloom #else !USG
105*33563Srick 		ttbuf_flags = ttbuf.sg_flags;
106*33563Srick 		ttbuf.sg_flags = ANYP|CBREAK;
10725130Sbloom 		ret = ioctl(Ifn, TCSETA, &ttbuf);
10825130Sbloom 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
109*33563Srick 		/* this is two seperate ioctls to set the x.29 params */
110*33563Srick 		ttbuf.sg_flags |= TANDEM;
111*33563Srick 		ret = ioctl(Ifn, TCSETA, &ttbuf);
112*33563Srick 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
113*33563Srick 		ttbuf.sg_flags = ttbuf_flags;
114*33563Srick #endif USG
11525130Sbloom 	}
11623599Sbloom 	fsig = signal(SIGALRM, falarm);
11723599Sbloom 	/* give the other side time to perform its ioctl;
11823599Sbloom 	 * otherwise it may flush out the first data this
11923599Sbloom 	 * side is about to send.
12023599Sbloom 	 */
12123599Sbloom 	sleep(2);
12223599Sbloom 	return SUCCESS;
12323599Sbloom }
12423599Sbloom 
12523599Sbloom fturnoff()
12623599Sbloom {
127*33563Srick 	if (!IsTcpIp)
128*33563Srick 		ioctl(Ifn, TCSETA, &ttbuf);
12923599Sbloom 	(void) signal(SIGALRM, fsig);
130*33563Srick 	sleep(2);
13123599Sbloom 	return SUCCESS;
13223599Sbloom }
13323599Sbloom 
13423599Sbloom fwrmsg(type, str, fn)
13523599Sbloom register char *str;
13623599Sbloom int fn;
13723599Sbloom char type;
13823599Sbloom {
13923599Sbloom 	register char *s;
14023599Sbloom 	char bufr[MAXMSGLEN];
14123599Sbloom 
14223599Sbloom 	s = bufr;
14323599Sbloom 	*s++ = type;
14423599Sbloom 	while (*str)
14523599Sbloom 		*s++ = *str++;
14623599Sbloom 	if (*(s-1) == '\n')
14723599Sbloom 		s--;
14823599Sbloom 	*s++ = '\r';
14925130Sbloom 	*s = 0;
15023599Sbloom 	(void) write(fn, bufr, s - bufr);
15123599Sbloom 	return SUCCESS;
15223599Sbloom }
15323599Sbloom 
15423599Sbloom frdmsg(str, fn)
15523599Sbloom register char *str;
15623599Sbloom register int fn;
15723599Sbloom {
15823599Sbloom 	register char *smax;
15923599Sbloom 
16023599Sbloom 	if (setjmp(Ffailbuf))
16123599Sbloom 		return FAIL;
16223599Sbloom 	smax = str + MAXMSGLEN - 1;
16323599Sbloom 	(void) alarm(2*MAXMSGTIME);
16423599Sbloom 	for (;;) {
16523599Sbloom 		if (read(fn, str, 1) <= 0)
16623599Sbloom 			goto msgerr;
16725130Sbloom 		*str &= 0177;
16823599Sbloom 		if (*str == '\r')
16923599Sbloom 			break;
17025130Sbloom 		if (*str < ' ') {
17123599Sbloom 			continue;
17225130Sbloom 		}
17323599Sbloom 		if (str++ >= smax)
17423599Sbloom 			goto msgerr;
17523599Sbloom 	}
17623599Sbloom 	*str = '\0';
17723599Sbloom 	(void) alarm(0);
17823599Sbloom 	return SUCCESS;
17923599Sbloom msgerr:
18023599Sbloom 	(void) alarm(0);
18123599Sbloom 	return FAIL;
18223599Sbloom }
18323599Sbloom 
18423599Sbloom fwrdata(fp1, fn)
18523599Sbloom FILE *fp1;
18623599Sbloom int fn;
18723599Sbloom {
18825130Sbloom 	register int alen, ret;
18925130Sbloom 	char ack, ibuf[MAXMSGLEN];
19025130Sbloom 	int flen, mil, retries = 0;
19123599Sbloom 	long abytes, fbytes;
19223599Sbloom 	struct timeb t1, t2;
193*33563Srick 	float ft;
19423599Sbloom 
19523599Sbloom 	ret = FAIL;
19623599Sbloom retry:
19723599Sbloom 	fchksum = 0xffff;
19823599Sbloom 	abytes = fbytes = 0L;
19923599Sbloom 	ack = '\0';
20023599Sbloom #ifdef USG
20123599Sbloom 	time(&t1.time);
20223599Sbloom 	t1.millitm = 0;
20323599Sbloom #else !USG
20423599Sbloom 	ftime(&t1);
20523599Sbloom #endif !USG
20625130Sbloom 	do {
20725130Sbloom 		alen = fwrblk(fn, fp1, &flen);
20825130Sbloom 		fbytes += flen;
20925130Sbloom 		if (alen <= 0) {
21025130Sbloom 			abytes -= alen;
21123599Sbloom 			goto acct;
21223599Sbloom 		}
21325130Sbloom 		abytes += alen;
21425130Sbloom 	} while (!feof(fp1) && !ferror(fp1));
21525130Sbloom 	DEBUG(8, "\nchecksum: %04x\n", fchksum);
21625130Sbloom 	if (frdmsg(ibuf, fn) != FAIL) {
21725130Sbloom 		if ((ack = ibuf[0]) == 'G')
21825130Sbloom 			ret = SUCCESS;
21925130Sbloom 		DEBUG(4, "ack - '%c'\n", ack);
22023599Sbloom 	}
22123599Sbloom acct:
22223599Sbloom #ifdef USG
22323599Sbloom 	time(&t2.time);
22423599Sbloom 	t2.millitm = 0;
22523599Sbloom #else !USG
22623599Sbloom 	ftime(&t2);
22723599Sbloom #endif !USG
22823599Sbloom 	Now = t2;
22923599Sbloom 	t2.time -= t1.time;
23023599Sbloom 	mil = t2.millitm - t1.millitm;
23123599Sbloom 	if (mil < 0) {
23223599Sbloom 		--t2.time;
23323599Sbloom 		mil += 1000;
23423599Sbloom 	}
235*33563Srick 	ft = (float)t2.time + (float)mil/1000.;
236*33563Srick 	sprintf(ibuf, "sent data %ld bytes %.2f secs %ld bps",
237*33563Srick 		fbytes, ft, (long)((float)fbytes*8./ft));
23825149Sbloom 	sysacct(abytes, t2.time);
239*33563Srick 	Bytes_Sent += fbytes;
24025130Sbloom 	if (retries > 0)
24125130Sbloom 		sprintf(&ibuf[strlen(ibuf)], ", %d retries", retries);
24223599Sbloom 	DEBUG(1, "%s\n", ibuf);
24323599Sbloom 	syslog(ibuf);
24425130Sbloom 	if (ack == 'R') {
24525130Sbloom 		DEBUG(4, "RETRY:\n", 0);
24625130Sbloom 		fseek(fp1, 0L, 0);
24725130Sbloom 		retries++;
24825130Sbloom 		goto retry;
24925130Sbloom 	}
25023599Sbloom #ifdef SYSACCT
25125130Sbloom 	if (ret == FAIL)
25223599Sbloom 		sysaccf(NULL);		/* force accounting */
25323599Sbloom #endif SYSACCT
25423599Sbloom 	return ret;
25523599Sbloom }
25623599Sbloom 
25723599Sbloom /* max. attempts to retransmit a file: */
25823599Sbloom #define MAXRETRIES	(fbytes < 10000L ? 2 : 1)
25923599Sbloom 
26023599Sbloom frddata(fn, fp2)
26123599Sbloom register int fn;
26223599Sbloom register FILE *fp2;
26323599Sbloom {
26423599Sbloom 	register int flen;
26523599Sbloom 	register char eof;
26625130Sbloom 	char ibuf[FIBUFSIZ];
26725130Sbloom 	int ret, mil, retries = 0;
26823599Sbloom 	long alen, abytes, fbytes;
26923599Sbloom 	struct timeb t1, t2;
270*33563Srick 	float ft;
27123599Sbloom 
27223599Sbloom 	ret = FAIL;
27323599Sbloom retry:
27423599Sbloom 	fchksum = 0xffff;
27523599Sbloom 	abytes = fbytes = 0L;
27623599Sbloom #ifdef USG
27723599Sbloom 	time(&t1.time);
27823599Sbloom 	t1.millitm = 0;
27923599Sbloom #else !USG
28023599Sbloom 	ftime(&t1);
28123599Sbloom #endif !USG
28223599Sbloom 	do {
28323599Sbloom 		flen = frdblk(ibuf, fn, &alen);
28423599Sbloom 		abytes += alen;
28523599Sbloom 		if (flen < 0)
28623599Sbloom 			goto acct;
28725130Sbloom 		if (eof = flen > FIBUFSIZ)
28825130Sbloom 			flen -= FIBUFSIZ + 1;
28923599Sbloom 		fbytes += flen;
29023599Sbloom 		if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
29123599Sbloom 			goto acct;
29223599Sbloom 	} while (!eof);
29325130Sbloom 	ret = SUCCESS;
29423599Sbloom acct:
29523599Sbloom #ifdef USG
29623599Sbloom 	time(&t2.time);
29723599Sbloom 	t2.millitm = 0;
29823599Sbloom #else !USG
29923599Sbloom 	ftime(&t2);
30023599Sbloom #endif !USG
30123599Sbloom 	Now = t2;
30223599Sbloom 	t2.time -= t1.time;
30323599Sbloom 	mil = t2.millitm - t1.millitm;
30423599Sbloom 	if (mil < 0) {
30523599Sbloom 		--t2.time;
30623599Sbloom 		mil += 1000;
30723599Sbloom 	}
308*33563Srick 	ft = (float)t2.time + (float)mil/1000.;
309*33563Srick 	sprintf(ibuf, "received data %ld bytes %.2f secs %ld bps",
310*33563Srick 		fbytes, ft, (long)((float)fbytes*8./ft));
31125130Sbloom 	if (retries > 0)
31225130Sbloom 		sprintf(&ibuf[strlen(ibuf)]," %d retries", retries);
31325149Sbloom 	sysacct(abytes, t2.time);
314*33563Srick 	Bytes_Received += fbytes;
31523599Sbloom 	DEBUG(1, "%s\n", ibuf);
31623599Sbloom 	syslog(ibuf);
31725130Sbloom 	if (ret == FAIL) {
31825130Sbloom 		if (retries++ < MAXRETRIES) {
31925130Sbloom 			DEBUG(8, "send ack: 'R'\n", 0);
32025130Sbloom 			fwrmsg('R', "", fn);
32125130Sbloom 			fseek(fp2, 0L, 0);
32225130Sbloom 			DEBUG(4, "RETRY:\n", 0);
32325130Sbloom 			goto retry;
32425130Sbloom 		}
32525130Sbloom 		DEBUG(8, "send ack: 'Q'\n", 0);
32625130Sbloom 		fwrmsg('Q', "", fn);
32725130Sbloom #ifdef SYSACCT
32825130Sbloom 		sysaccf(NULL);		/* force accounting */
32925130Sbloom #endif SYSACCT
33025130Sbloom 	}
33125130Sbloom 	else {
33225130Sbloom 		DEBUG(8, "send ack: 'G'\n", 0);
33325130Sbloom 		fwrmsg('G', "", fn);
33425130Sbloom 	}
33523599Sbloom 	return ret;
33623599Sbloom }
33723599Sbloom 
33823599Sbloom static
33923599Sbloom frdbuf(blk, len, fn)
34023599Sbloom register char *blk;
34123599Sbloom register int len;
34223599Sbloom register int fn;
34323599Sbloom {
34425130Sbloom 	static int ret = FIBUFSIZ / 2;
34523599Sbloom 
34623599Sbloom 	if (setjmp(Ffailbuf))
34723599Sbloom 		return FAIL;
34823599Sbloom 	(void) alarm(MAXMSGTIME);
34923599Sbloom 	ret = read(fn, blk, len);
35023599Sbloom 	alarm(0);
35123599Sbloom 	return ret <= 0 ? FAIL : ret;
35223599Sbloom }
35323599Sbloom 
35425130Sbloom #if !defined(BSD4_2) && !defined(USG)
35523599Sbloom /* call ultouch every TC calls to either frdblk or fwrblk  */
35625130Sbloom #define TC	20
35725130Sbloom static int tc = TC;
35825130Sbloom #endif !defined(BSD4_2) && !defined(USG)
35923599Sbloom 
36023599Sbloom /* Byte conversion:
36123599Sbloom  *
36225130Sbloom  *   from	 pre	   to
36325130Sbloom  * 000-037	 172	 100-137
36425130Sbloom  * 040-171		 040-171
36525130Sbloom  * 172-177	 173	 072-077
36625130Sbloom  * 200-237	 174	 100-137
36725130Sbloom  * 240-371	 175	 040-171
36825130Sbloom  * 372-377	 176	 072-077
36923599Sbloom  */
37023599Sbloom 
37123599Sbloom static
37225130Sbloom fwrblk(fn, fp, lenp)
37323599Sbloom int fn;
37425130Sbloom register FILE *fp;
37525130Sbloom int *lenp;
37623599Sbloom {
37723599Sbloom 	register char *op;
37825130Sbloom 	register int c, sum, nl, len;
37925130Sbloom 	char obuf[FOBUFSIZ + 8];
38023599Sbloom 	int ret;
38123599Sbloom 
38225130Sbloom #if !defined(BSD4_2) && !defined(USG)
38323599Sbloom 	/* call ultouch occasionally */
38423599Sbloom 	if (--tc < 0) {
38523599Sbloom 		tc = TC;
38623599Sbloom 		ultouch();
38723599Sbloom 	}
38825130Sbloom #endif !defined(BSD4_2) && !defined(USG)
38923599Sbloom 	op = obuf;
39023599Sbloom 	nl = 0;
39125130Sbloom 	len = 0;
39223599Sbloom 	sum = fchksum;
39325130Sbloom 	while ((c = getc(fp)) != EOF) {
39425130Sbloom 		len++;
39523599Sbloom 		if (sum & 0x8000) {
39623599Sbloom 			sum <<= 1;
39723599Sbloom 			sum++;
39823599Sbloom 		} else
39923599Sbloom 			sum <<= 1;
40025130Sbloom 		sum += c;
40123599Sbloom 		sum &= 0xffff;
40225130Sbloom 		if (c & 0200) {
40325130Sbloom 			c &= 0177;
40425130Sbloom 			if (c < 040) {
40523599Sbloom 				*op++ = '\174';
40625130Sbloom 				*op++ = c + 0100;
40723599Sbloom 			} else
40825130Sbloom 			if (c <= 0171) {
40923599Sbloom 				*op++ = '\175';
41025130Sbloom 				*op++ = c;
41123599Sbloom 			}
41223599Sbloom 			else {
41323599Sbloom 				*op++ = '\176';
41425130Sbloom 				*op++ = c - 0100;
41523599Sbloom 			}
41623599Sbloom 			nl += 2;
41723599Sbloom 		} else {
41825130Sbloom 			if (c < 040) {
41923599Sbloom 				*op++ = '\172';
42025130Sbloom 				*op++ = c + 0100;
42123599Sbloom 				nl += 2;
42223599Sbloom 			} else
42325130Sbloom 			if (c <= 0171) {
42425130Sbloom 				*op++ = c;
42523599Sbloom 				nl++;
42623599Sbloom 			} else {
42723599Sbloom 				*op++ = '\173';
42825130Sbloom 				*op++ = c - 0100;
42923599Sbloom 				nl += 2;
43023599Sbloom 			}
43123599Sbloom 		}
43225130Sbloom 		if (nl >= FOBUFSIZ - 1) {
43325130Sbloom 			/*
43425130Sbloom 			 * peek at next char, see if it will fit
43525130Sbloom 			 */
43625130Sbloom 			c = getc(fp);
43725130Sbloom 			if (c == EOF)
43825130Sbloom 				break;
43925130Sbloom 			(void) ungetc(c, fp);
44025130Sbloom 			if (nl >= FOBUFSIZ || c < 040 || c > 0171)
44125130Sbloom 				goto writeit;
44225130Sbloom 		}
44325130Sbloom 	}
44425130Sbloom 	/*
44525130Sbloom 	 * At EOF - append checksum, there is space for it...
44625130Sbloom 	 */
44725130Sbloom 	sprintf(op, "\176\176%04x\r", sum);
44825130Sbloom 	nl += strlen(op);
44925130Sbloom writeit:
45025130Sbloom 	*lenp = len;
45123599Sbloom 	fchksum = sum;
45225130Sbloom 	DEBUG(8, "%d/", len);
45323599Sbloom 	DEBUG(8, "%d,", nl);
45423599Sbloom 	ret = write(fn, obuf, nl);
45523599Sbloom 	return ret == nl ? nl : ret < 0 ? 0 : -ret;
45623599Sbloom }
45723599Sbloom 
45823599Sbloom static
45923599Sbloom frdblk(ip, fn, rlen)
46023599Sbloom register char *ip;
46123599Sbloom int fn;
46223599Sbloom long *rlen;
46323599Sbloom {
46423599Sbloom 	register char *op, c;
46523599Sbloom 	register int sum, len, nl;
46623599Sbloom 	char buf[5], *erbp = ip;
46723599Sbloom 	int i;
46823599Sbloom 	static char special = 0;
46923599Sbloom 
47025130Sbloom #if !defined(BSD4_2) && !defined(USG)
47123599Sbloom 	/* call ultouch occasionally */
47223599Sbloom 	if (--tc < 0) {
47323599Sbloom 		tc = TC;
47423599Sbloom 		ultouch();
47523599Sbloom 	}
47625130Sbloom #endif !defined(BSD4_2) && !defined(USG)
47725130Sbloom 	if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) {
47823599Sbloom 		*rlen = 0;
47923599Sbloom 		goto dcorr;
48023599Sbloom 	}
48123599Sbloom 	*rlen = len;
48223599Sbloom 	DEBUG(8, "%d/", len);
48323599Sbloom 	op = ip;
48423599Sbloom 	nl = 0;
48523599Sbloom 	sum = fchksum;
48623599Sbloom 	do {
48723599Sbloom 		if ((*ip &= 0177) >= '\172') {
48823599Sbloom 			if (special) {
48923599Sbloom 				DEBUG(8, "%d", nl);
49023599Sbloom 				special = 0;
49123599Sbloom 				op = buf;
49223599Sbloom 				if (*ip++ != '\176' || (i = --len) > 5)
49323599Sbloom 					goto dcorr;
49423599Sbloom 				while (i--)
49525130Sbloom 					*op++ = *ip++ & 0177;
49623599Sbloom 				while (len < 5) {
49723599Sbloom 					i = frdbuf(&buf[len], 5 - len, fn);
49823599Sbloom 					if (i == FAIL) {
49923599Sbloom 						len = FAIL;
50023599Sbloom 						goto dcorr;
50123599Sbloom 					}
50223599Sbloom 					DEBUG(8, ",%d", i);
50323599Sbloom 					len += i;
50423599Sbloom 					*rlen += i;
50525130Sbloom 					while (i--)
50625130Sbloom 						*op++ &= 0177;
50723599Sbloom 				}
50823599Sbloom 				if (buf[4] != '\r')
50923599Sbloom 					goto dcorr;
51023599Sbloom 				sscanf(buf, "%4x", &fchksum);
51123599Sbloom 				DEBUG(8, "\nchecksum: %04x\n", sum);
51223599Sbloom 				if (fchksum == sum)
51325130Sbloom 					return FIBUFSIZ + 1 + nl;
51423599Sbloom 				else {
51523599Sbloom 					DEBUG(8, "\n", 0);
51623599Sbloom 					DEBUG(4, "Bad checksum\n", 0);
51723599Sbloom 					return FAIL;
51823599Sbloom 				}
51923599Sbloom 			}
52023599Sbloom 			special = *ip++;
52123599Sbloom 		} else {
52223599Sbloom 			if (*ip < '\040') {
52323599Sbloom 				/* error: shouldn't get control chars */
52423599Sbloom 				goto dcorr;
52523599Sbloom 			}
52623599Sbloom 			switch (special) {
52723599Sbloom 			case 0:
52823599Sbloom 				c = *ip++;
52923599Sbloom 				break;
53023599Sbloom 			case '\172':
53123599Sbloom 				c = *ip++ - 0100;
53223599Sbloom 				break;
53323599Sbloom 			case '\173':
53423599Sbloom 				c = *ip++ + 0100;
53523599Sbloom 				break;
53623599Sbloom 			case '\174':
53723599Sbloom 				c = *ip++ + 0100;
53823599Sbloom 				break;
53923599Sbloom 			case '\175':
54023599Sbloom 				c = *ip++ + 0200;
54123599Sbloom 				break;
54223599Sbloom 			case '\176':
54323599Sbloom 				c = *ip++ + 0300;
54423599Sbloom 				break;
54523599Sbloom 			}
54623599Sbloom 			*op++ = c;
54723599Sbloom 			if (sum & 0x8000) {
54823599Sbloom 				sum <<= 1;
54923599Sbloom 				sum++;
55023599Sbloom 			} else
55123599Sbloom 				sum <<= 1;
55223599Sbloom 			sum += c & 0377;
55323599Sbloom 			sum &= 0xffff;
55423599Sbloom 			special = 0;
55523599Sbloom 			nl++;
55623599Sbloom 		}
55723599Sbloom 	} while (--len);
55823599Sbloom 	fchksum = sum;
55923599Sbloom 	DEBUG(8, "%d,", nl);
56023599Sbloom 	return nl;
56123599Sbloom dcorr:
56223599Sbloom 	DEBUG(8, "\n", 0);
56323599Sbloom 	DEBUG(4, "Data corrupted\n", 0);
56423599Sbloom 	while (len != FAIL) {
56525130Sbloom 		if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL)
56623599Sbloom 			*rlen += len;
56723599Sbloom 	}
56823599Sbloom 	return FAIL;
56923599Sbloom }
57025130Sbloom 
571