147438Sbostic /*-
2*62391Sbostic * Copyright (c) 1985, 1993
3*62391Sbostic * The Regents of the University of California. All rights reserved.
447438Sbostic *
547438Sbostic * This code is derived from software contributed to Berkeley by
647438Sbostic * Rick Adams.
747438Sbostic *
847438Sbostic * %sccs.include.redist.c%
947438Sbostic */
1047438Sbostic
1123599Sbloom #ifndef lint
12*62391Sbostic static char sccsid[] = "@(#)fio.c 8.1 (Berkeley) 06/06/93";
1347438Sbostic #endif /* not lint */
1423599Sbloom
1523599Sbloom /*
1623599Sbloom * flow control protocol.
1723599Sbloom *
1823599Sbloom * This protocol relies on flow control of the data stream.
1923599Sbloom * It is meant for working over links that can (almost) be
2023599Sbloom * guaranteed to be errorfree, specifically X.25/PAD links.
2123599Sbloom * A sumcheck is carried out over a whole file only. If a
2223599Sbloom * transport fails the receiver can request retransmission(s).
2323599Sbloom * This protocol uses a 7-bit datapath only, so it can be
2423599Sbloom * used on links that are not 8-bit transparent.
2523599Sbloom *
2623599Sbloom * When using this protocol with an X.25 PAD:
2723599Sbloom * Although this protocol uses no control chars except CR,
2823599Sbloom * control chars NULL and ^P are used before this protocol
2923599Sbloom * is started; since ^P is the default char for accessing
3023599Sbloom * PAD X.28 command mode, be sure to disable that access
3123599Sbloom * (PAD par 1). Also make sure both flow control pars
3223599Sbloom * (5 and 12) are set. The CR used in this proto is meant
3323599Sbloom * to trigger packet transmission, hence par 3 should be
3423599Sbloom * set to 2; a good value for the Idle Timer (par 4) is 10.
3523599Sbloom * All other pars should be set to 0.
3625130Sbloom *
3723599Sbloom * Normally a calling site will take care of setting the
3823599Sbloom * local PAD pars via an X.28 command and those of the remote
3923599Sbloom * PAD via an X.29 command, unless the remote site has a
4023599Sbloom * special channel assigned for this protocol with the proper
4123599Sbloom * par settings.
4223599Sbloom *
4325130Sbloom * Additional comments for hosts with direct X.25 access:
4425130Sbloom * - the global variable IsTcpIp, when set, excludes the ioctl's,
4525130Sbloom * so the same binary can run on X.25 and non-X.25 hosts;
4625130Sbloom * - reads are done in small chunks, which can be smaller than
4725130Sbloom * the packet size; your X.25 driver must support that.
4825130Sbloom *
4925130Sbloom *
5025130Sbloom * Author:
5125130Sbloom * Piet Beertema, CWI, Amsterdam, Sep 1984
5225130Sbloom * Modified for X.25 hosts:
5325130Sbloom * Robert Elz, Melbourne Univ, Mar 1985
5423599Sbloom */
5523599Sbloom
5625130Sbloom #include "uucp.h"
5723599Sbloom #include <signal.h>
5823599Sbloom #ifdef USG
5923599Sbloom #include <termio.h>
6023599Sbloom #else !USG
6123599Sbloom #include <sgtty.h>
6223599Sbloom #endif !USG
6323599Sbloom #include <setjmp.h>
6423599Sbloom
6533563Srick #define FIBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size,
6625130Sbloom * but see comment above
6725130Sbloom */
6823599Sbloom
6933563Srick #define FOBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size;
7025130Sbloom * otherwise make as large as feasible to reduce
7125130Sbloom * number of write system calls
7225130Sbloom */
7325130Sbloom
7423599Sbloom #ifndef MAXMSGLEN
7523599Sbloom #define MAXMSGLEN BUFSIZ
7623599Sbloom #endif MAXMSGLEN
7723599Sbloom
7823599Sbloom static int fchksum;
7923599Sbloom static jmp_buf Ffailbuf;
8023599Sbloom
8133563Srick extern long Bytes_Sent, Bytes_Received;
8233563Srick
8346879Sbostic static void
falarm()8423599Sbloom falarm()
8523599Sbloom {
8623599Sbloom signal(SIGALRM, falarm);
8723599Sbloom longjmp(Ffailbuf, 1);
8823599Sbloom }
8923599Sbloom
9044710Strent static void (*fsig)();
9123599Sbloom
9223599Sbloom #ifndef USG
9323599Sbloom #define TCGETA TIOCGETP
9433969Srick #define TCSETAF TIOCSETP
9523599Sbloom #define termio sgttyb
9623599Sbloom #endif USG
9733563Srick static struct termio ttbuf;
9823599Sbloom
fturnon()9923599Sbloom fturnon()
10023599Sbloom {
10133563Srick int ttbuf_flags;
10223599Sbloom
10325130Sbloom if (!IsTcpIp) {
10425130Sbloom ioctl(Ifn, TCGETA, &ttbuf);
10523599Sbloom #ifdef USG
10633563Srick ttbuf_flags = ttbuf.c_iflag;
10725130Sbloom ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
10825130Sbloom ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ;
10925130Sbloom ttbuf.c_cc[VTIME] = 5;
11033969Srick if (ioctl(Ifn, TCSETAF, &ttbuf) < 0) {
11133969Srick syslog(LOG_ERR, "ioctl(TCSETAF) failed: %m");
11233969Srick cleanup(FAIL);
11333969Srick }
11433563Srick ttbuf.c_iflag = ttbuf_flags;
11525130Sbloom #else !USG
11633563Srick ttbuf_flags = ttbuf.sg_flags;
11733563Srick ttbuf.sg_flags = ANYP|CBREAK;
11833969Srick if (ioctl(Ifn, TCSETAF, &ttbuf) < 0) {
11933969Srick syslog(LOG_ERR, "ioctl(TCSETAF) failed: %m");
12033969Srick cleanup(FAIL);
12133969Srick }
12233563Srick /* this is two seperate ioctls to set the x.29 params */
12333563Srick ttbuf.sg_flags |= TANDEM;
12433969Srick if (ioctl(Ifn, TCSETAF, &ttbuf) < 0) {
12533969Srick syslog(LOG_ERR, "ioctl(TCSETAF) failed: %m");
12633969Srick cleanup(FAIL);
12733969Srick }
12833563Srick ttbuf.sg_flags = ttbuf_flags;
12933563Srick #endif USG
13025130Sbloom }
13123599Sbloom fsig = signal(SIGALRM, falarm);
13223599Sbloom /* give the other side time to perform its ioctl;
13323599Sbloom * otherwise it may flush out the first data this
13423599Sbloom * side is about to send.
13523599Sbloom */
13623599Sbloom sleep(2);
13723599Sbloom return SUCCESS;
13823599Sbloom }
13923599Sbloom
fturnoff()14023599Sbloom fturnoff()
14123599Sbloom {
14233563Srick if (!IsTcpIp)
14333969Srick ioctl(Ifn, TCSETAF, &ttbuf);
14423599Sbloom (void) signal(SIGALRM, fsig);
14533563Srick sleep(2);
14623599Sbloom return SUCCESS;
14723599Sbloom }
14823599Sbloom
fwrmsg(type,str,fn)14923599Sbloom fwrmsg(type, str, fn)
15023599Sbloom register char *str;
15123599Sbloom int fn;
15223599Sbloom char type;
15323599Sbloom {
15423599Sbloom register char *s;
15523599Sbloom char bufr[MAXMSGLEN];
15623599Sbloom
15723599Sbloom s = bufr;
15823599Sbloom *s++ = type;
15923599Sbloom while (*str)
16023599Sbloom *s++ = *str++;
16123599Sbloom if (*(s-1) == '\n')
16223599Sbloom s--;
16323599Sbloom *s++ = '\r';
16425130Sbloom *s = 0;
16523599Sbloom (void) write(fn, bufr, s - bufr);
16623599Sbloom return SUCCESS;
16723599Sbloom }
16823599Sbloom
frdmsg(str,fn)16923599Sbloom frdmsg(str, fn)
17023599Sbloom register char *str;
17123599Sbloom register int fn;
17223599Sbloom {
17323599Sbloom register char *smax;
17423599Sbloom
17523599Sbloom if (setjmp(Ffailbuf))
17623599Sbloom return FAIL;
17723599Sbloom smax = str + MAXMSGLEN - 1;
17823599Sbloom (void) alarm(2*MAXMSGTIME);
17923599Sbloom for (;;) {
18023599Sbloom if (read(fn, str, 1) <= 0)
18123599Sbloom goto msgerr;
18225130Sbloom *str &= 0177;
18323599Sbloom if (*str == '\r')
18423599Sbloom break;
18525130Sbloom if (*str < ' ') {
18623599Sbloom continue;
18725130Sbloom }
18823599Sbloom if (str++ >= smax)
18923599Sbloom goto msgerr;
19023599Sbloom }
19123599Sbloom *str = '\0';
19223599Sbloom (void) alarm(0);
19323599Sbloom return SUCCESS;
19423599Sbloom msgerr:
19523599Sbloom (void) alarm(0);
19623599Sbloom return FAIL;
19723599Sbloom }
19823599Sbloom
fwrdata(fp1,fn)19923599Sbloom fwrdata(fp1, fn)
20023599Sbloom FILE *fp1;
20123599Sbloom int fn;
20223599Sbloom {
20325130Sbloom register int alen, ret;
20425130Sbloom char ack, ibuf[MAXMSGLEN];
20525130Sbloom int flen, mil, retries = 0;
20623599Sbloom long abytes, fbytes;
20723599Sbloom struct timeb t1, t2;
20833563Srick float ft;
20946879Sbostic static int fwrblk();
21023599Sbloom
21123599Sbloom ret = FAIL;
21223599Sbloom retry:
21323599Sbloom fchksum = 0xffff;
21423599Sbloom abytes = fbytes = 0L;
21523599Sbloom ack = '\0';
21623599Sbloom #ifdef USG
21723599Sbloom time(&t1.time);
21823599Sbloom t1.millitm = 0;
21923599Sbloom #else !USG
22023599Sbloom ftime(&t1);
22123599Sbloom #endif !USG
22225130Sbloom do {
22325130Sbloom alen = fwrblk(fn, fp1, &flen);
22425130Sbloom fbytes += flen;
22525130Sbloom if (alen <= 0) {
22625130Sbloom abytes -= alen;
22723599Sbloom goto acct;
22823599Sbloom }
22925130Sbloom abytes += alen;
23025130Sbloom } while (!feof(fp1) && !ferror(fp1));
23125130Sbloom DEBUG(8, "\nchecksum: %04x\n", fchksum);
23225130Sbloom if (frdmsg(ibuf, fn) != FAIL) {
23325130Sbloom if ((ack = ibuf[0]) == 'G')
23425130Sbloom ret = SUCCESS;
23525130Sbloom DEBUG(4, "ack - '%c'\n", ack);
23623599Sbloom }
23723599Sbloom acct:
23823599Sbloom #ifdef USG
23923599Sbloom time(&t2.time);
24023599Sbloom t2.millitm = 0;
24123599Sbloom #else !USG
24223599Sbloom ftime(&t2);
24323599Sbloom #endif !USG
24423599Sbloom Now = t2;
24523599Sbloom t2.time -= t1.time;
24623599Sbloom mil = t2.millitm - t1.millitm;
24723599Sbloom if (mil < 0) {
24823599Sbloom --t2.time;
24923599Sbloom mil += 1000;
25023599Sbloom }
25133563Srick ft = (float)t2.time + (float)mil/1000.;
25233563Srick sprintf(ibuf, "sent data %ld bytes %.2f secs %ld bps",
25333563Srick fbytes, ft, (long)((float)fbytes*8./ft));
25425149Sbloom sysacct(abytes, t2.time);
25533563Srick Bytes_Sent += fbytes;
25625130Sbloom if (retries > 0)
25725130Sbloom sprintf(&ibuf[strlen(ibuf)], ", %d retries", retries);
25823599Sbloom DEBUG(1, "%s\n", ibuf);
25933969Srick log_xferstats(ibuf);
26025130Sbloom if (ack == 'R') {
26125130Sbloom DEBUG(4, "RETRY:\n", 0);
26225130Sbloom fseek(fp1, 0L, 0);
26325130Sbloom retries++;
26425130Sbloom goto retry;
26525130Sbloom }
26623599Sbloom #ifdef SYSACCT
26725130Sbloom if (ret == FAIL)
26823599Sbloom sysaccf(NULL); /* force accounting */
26923599Sbloom #endif SYSACCT
27023599Sbloom return ret;
27123599Sbloom }
27223599Sbloom
27323599Sbloom /* max. attempts to retransmit a file: */
27423599Sbloom #define MAXRETRIES (fbytes < 10000L ? 2 : 1)
27523599Sbloom
frddata(fn,fp2)27623599Sbloom frddata(fn, fp2)
27723599Sbloom register int fn;
27823599Sbloom register FILE *fp2;
27923599Sbloom {
28023599Sbloom register int flen;
28123599Sbloom register char eof;
28225130Sbloom char ibuf[FIBUFSIZ];
28325130Sbloom int ret, mil, retries = 0;
28423599Sbloom long alen, abytes, fbytes;
28523599Sbloom struct timeb t1, t2;
28633563Srick float ft;
28746879Sbostic static int frdblk();
28823599Sbloom
28923599Sbloom ret = FAIL;
29023599Sbloom retry:
29123599Sbloom fchksum = 0xffff;
29223599Sbloom abytes = fbytes = 0L;
29323599Sbloom #ifdef USG
29423599Sbloom time(&t1.time);
29523599Sbloom t1.millitm = 0;
29623599Sbloom #else !USG
29723599Sbloom ftime(&t1);
29823599Sbloom #endif !USG
29923599Sbloom do {
30023599Sbloom flen = frdblk(ibuf, fn, &alen);
30123599Sbloom abytes += alen;
30223599Sbloom if (flen < 0)
30323599Sbloom goto acct;
30425130Sbloom if (eof = flen > FIBUFSIZ)
30525130Sbloom flen -= FIBUFSIZ + 1;
30623599Sbloom fbytes += flen;
30723599Sbloom if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
30823599Sbloom goto acct;
30923599Sbloom } while (!eof);
31025130Sbloom ret = SUCCESS;
31123599Sbloom acct:
31223599Sbloom #ifdef USG
31323599Sbloom time(&t2.time);
31423599Sbloom t2.millitm = 0;
31523599Sbloom #else !USG
31623599Sbloom ftime(&t2);
31723599Sbloom #endif !USG
31823599Sbloom Now = t2;
31923599Sbloom t2.time -= t1.time;
32023599Sbloom mil = t2.millitm - t1.millitm;
32123599Sbloom if (mil < 0) {
32223599Sbloom --t2.time;
32323599Sbloom mil += 1000;
32423599Sbloom }
32533563Srick ft = (float)t2.time + (float)mil/1000.;
32633563Srick sprintf(ibuf, "received data %ld bytes %.2f secs %ld bps",
32733563Srick fbytes, ft, (long)((float)fbytes*8./ft));
32825130Sbloom if (retries > 0)
32925130Sbloom sprintf(&ibuf[strlen(ibuf)]," %d retries", retries);
33025149Sbloom sysacct(abytes, t2.time);
33133563Srick Bytes_Received += fbytes;
33223599Sbloom DEBUG(1, "%s\n", ibuf);
33333969Srick log_xferstats(ibuf);
33425130Sbloom if (ret == FAIL) {
33525130Sbloom if (retries++ < MAXRETRIES) {
33625130Sbloom DEBUG(8, "send ack: 'R'\n", 0);
33725130Sbloom fwrmsg('R', "", fn);
33825130Sbloom fseek(fp2, 0L, 0);
33925130Sbloom DEBUG(4, "RETRY:\n", 0);
34025130Sbloom goto retry;
34125130Sbloom }
34225130Sbloom DEBUG(8, "send ack: 'Q'\n", 0);
34325130Sbloom fwrmsg('Q', "", fn);
34425130Sbloom #ifdef SYSACCT
34525130Sbloom sysaccf(NULL); /* force accounting */
34625130Sbloom #endif SYSACCT
34725130Sbloom }
34825130Sbloom else {
34925130Sbloom DEBUG(8, "send ack: 'G'\n", 0);
35025130Sbloom fwrmsg('G', "", fn);
35125130Sbloom }
35223599Sbloom return ret;
35323599Sbloom }
35423599Sbloom
35523599Sbloom static
frdbuf(blk,len,fn)35623599Sbloom frdbuf(blk, len, fn)
35723599Sbloom register char *blk;
35823599Sbloom register int len;
35923599Sbloom register int fn;
36023599Sbloom {
36125130Sbloom static int ret = FIBUFSIZ / 2;
36223599Sbloom
36323599Sbloom if (setjmp(Ffailbuf))
36423599Sbloom return FAIL;
36523599Sbloom (void) alarm(MAXMSGTIME);
36623599Sbloom ret = read(fn, blk, len);
36723599Sbloom alarm(0);
36823599Sbloom return ret <= 0 ? FAIL : ret;
36923599Sbloom }
37023599Sbloom
37125130Sbloom #if !defined(BSD4_2) && !defined(USG)
37223599Sbloom /* call ultouch every TC calls to either frdblk or fwrblk */
37325130Sbloom #define TC 20
37425130Sbloom static int tc = TC;
37525130Sbloom #endif !defined(BSD4_2) && !defined(USG)
37623599Sbloom
37723599Sbloom /* Byte conversion:
37823599Sbloom *
37925130Sbloom * from pre to
38025130Sbloom * 000-037 172 100-137
38125130Sbloom * 040-171 040-171
38225130Sbloom * 172-177 173 072-077
38325130Sbloom * 200-237 174 100-137
38425130Sbloom * 240-371 175 040-171
38525130Sbloom * 372-377 176 072-077
38623599Sbloom */
38723599Sbloom
38823599Sbloom static
fwrblk(fn,fp,lenp)38925130Sbloom fwrblk(fn, fp, lenp)
39023599Sbloom int fn;
39125130Sbloom register FILE *fp;
39225130Sbloom int *lenp;
39323599Sbloom {
39423599Sbloom register char *op;
39525130Sbloom register int c, sum, nl, len;
39625130Sbloom char obuf[FOBUFSIZ + 8];
39723599Sbloom int ret;
39823599Sbloom
39925130Sbloom #if !defined(BSD4_2) && !defined(USG)
40023599Sbloom /* call ultouch occasionally */
40123599Sbloom if (--tc < 0) {
40223599Sbloom tc = TC;
40323599Sbloom ultouch();
40423599Sbloom }
40525130Sbloom #endif !defined(BSD4_2) && !defined(USG)
40623599Sbloom op = obuf;
40723599Sbloom nl = 0;
40825130Sbloom len = 0;
40923599Sbloom sum = fchksum;
41025130Sbloom while ((c = getc(fp)) != EOF) {
41125130Sbloom len++;
41223599Sbloom if (sum & 0x8000) {
41323599Sbloom sum <<= 1;
41423599Sbloom sum++;
41523599Sbloom } else
41623599Sbloom sum <<= 1;
41725130Sbloom sum += c;
41823599Sbloom sum &= 0xffff;
41925130Sbloom if (c & 0200) {
42025130Sbloom c &= 0177;
42125130Sbloom if (c < 040) {
42223599Sbloom *op++ = '\174';
42325130Sbloom *op++ = c + 0100;
42423599Sbloom } else
42525130Sbloom if (c <= 0171) {
42623599Sbloom *op++ = '\175';
42725130Sbloom *op++ = c;
42823599Sbloom }
42923599Sbloom else {
43023599Sbloom *op++ = '\176';
43125130Sbloom *op++ = c - 0100;
43223599Sbloom }
43323599Sbloom nl += 2;
43423599Sbloom } else {
43525130Sbloom if (c < 040) {
43623599Sbloom *op++ = '\172';
43725130Sbloom *op++ = c + 0100;
43823599Sbloom nl += 2;
43923599Sbloom } else
44025130Sbloom if (c <= 0171) {
44125130Sbloom *op++ = c;
44223599Sbloom nl++;
44323599Sbloom } else {
44423599Sbloom *op++ = '\173';
44525130Sbloom *op++ = c - 0100;
44623599Sbloom nl += 2;
44723599Sbloom }
44823599Sbloom }
44925130Sbloom if (nl >= FOBUFSIZ - 1) {
45025130Sbloom /*
45125130Sbloom * peek at next char, see if it will fit
45225130Sbloom */
45325130Sbloom c = getc(fp);
45425130Sbloom if (c == EOF)
45525130Sbloom break;
45625130Sbloom (void) ungetc(c, fp);
45725130Sbloom if (nl >= FOBUFSIZ || c < 040 || c > 0171)
45825130Sbloom goto writeit;
45925130Sbloom }
46025130Sbloom }
46125130Sbloom /*
46225130Sbloom * At EOF - append checksum, there is space for it...
46325130Sbloom */
46425130Sbloom sprintf(op, "\176\176%04x\r", sum);
46525130Sbloom nl += strlen(op);
46625130Sbloom writeit:
46725130Sbloom *lenp = len;
46823599Sbloom fchksum = sum;
46925130Sbloom DEBUG(8, "%d/", len);
47023599Sbloom DEBUG(8, "%d,", nl);
47123599Sbloom ret = write(fn, obuf, nl);
47223599Sbloom return ret == nl ? nl : ret < 0 ? 0 : -ret;
47323599Sbloom }
47423599Sbloom
47523599Sbloom static
frdblk(ip,fn,rlen)47623599Sbloom frdblk(ip, fn, rlen)
47723599Sbloom register char *ip;
47823599Sbloom int fn;
47923599Sbloom long *rlen;
48023599Sbloom {
48123599Sbloom register char *op, c;
48223599Sbloom register int sum, len, nl;
48323599Sbloom char buf[5], *erbp = ip;
48423599Sbloom int i;
48523599Sbloom static char special = 0;
48623599Sbloom
48725130Sbloom #if !defined(BSD4_2) && !defined(USG)
48823599Sbloom /* call ultouch occasionally */
48923599Sbloom if (--tc < 0) {
49023599Sbloom tc = TC;
49123599Sbloom ultouch();
49223599Sbloom }
49325130Sbloom #endif !defined(BSD4_2) && !defined(USG)
49425130Sbloom if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) {
49523599Sbloom *rlen = 0;
49623599Sbloom goto dcorr;
49723599Sbloom }
49823599Sbloom *rlen = len;
49923599Sbloom DEBUG(8, "%d/", len);
50023599Sbloom op = ip;
50123599Sbloom nl = 0;
50223599Sbloom sum = fchksum;
50323599Sbloom do {
50423599Sbloom if ((*ip &= 0177) >= '\172') {
50523599Sbloom if (special) {
50623599Sbloom DEBUG(8, "%d", nl);
50723599Sbloom special = 0;
50823599Sbloom op = buf;
50923599Sbloom if (*ip++ != '\176' || (i = --len) > 5)
51023599Sbloom goto dcorr;
51123599Sbloom while (i--)
51225130Sbloom *op++ = *ip++ & 0177;
51323599Sbloom while (len < 5) {
51423599Sbloom i = frdbuf(&buf[len], 5 - len, fn);
51523599Sbloom if (i == FAIL) {
51623599Sbloom len = FAIL;
51723599Sbloom goto dcorr;
51823599Sbloom }
51923599Sbloom DEBUG(8, ",%d", i);
52023599Sbloom len += i;
52123599Sbloom *rlen += i;
52225130Sbloom while (i--)
52325130Sbloom *op++ &= 0177;
52423599Sbloom }
52523599Sbloom if (buf[4] != '\r')
52623599Sbloom goto dcorr;
52723599Sbloom sscanf(buf, "%4x", &fchksum);
52823599Sbloom DEBUG(8, "\nchecksum: %04x\n", sum);
52923599Sbloom if (fchksum == sum)
53025130Sbloom return FIBUFSIZ + 1 + nl;
53123599Sbloom else {
53223599Sbloom DEBUG(8, "\n", 0);
53323599Sbloom DEBUG(4, "Bad checksum\n", 0);
53423599Sbloom return FAIL;
53523599Sbloom }
53623599Sbloom }
53723599Sbloom special = *ip++;
53823599Sbloom } else {
53923599Sbloom if (*ip < '\040') {
54023599Sbloom /* error: shouldn't get control chars */
54123599Sbloom goto dcorr;
54223599Sbloom }
54323599Sbloom switch (special) {
54423599Sbloom case 0:
54523599Sbloom c = *ip++;
54623599Sbloom break;
54723599Sbloom case '\172':
54823599Sbloom c = *ip++ - 0100;
54923599Sbloom break;
55023599Sbloom case '\173':
55123599Sbloom c = *ip++ + 0100;
55223599Sbloom break;
55323599Sbloom case '\174':
55423599Sbloom c = *ip++ + 0100;
55523599Sbloom break;
55623599Sbloom case '\175':
55723599Sbloom c = *ip++ + 0200;
55823599Sbloom break;
55923599Sbloom case '\176':
56023599Sbloom c = *ip++ + 0300;
56123599Sbloom break;
56223599Sbloom }
56323599Sbloom *op++ = c;
56423599Sbloom if (sum & 0x8000) {
56523599Sbloom sum <<= 1;
56623599Sbloom sum++;
56723599Sbloom } else
56823599Sbloom sum <<= 1;
56923599Sbloom sum += c & 0377;
57023599Sbloom sum &= 0xffff;
57123599Sbloom special = 0;
57223599Sbloom nl++;
57323599Sbloom }
57423599Sbloom } while (--len);
57523599Sbloom fchksum = sum;
57623599Sbloom DEBUG(8, "%d,", nl);
57723599Sbloom return nl;
57823599Sbloom dcorr:
57923599Sbloom DEBUG(8, "\n", 0);
58023599Sbloom DEBUG(4, "Data corrupted\n", 0);
58123599Sbloom while (len != FAIL) {
58225130Sbloom if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL)
58323599Sbloom *rlen += len;
58423599Sbloom }
58523599Sbloom return FAIL;
58623599Sbloom }
58725130Sbloom
588