v08i050: UUCP X.25 'f' protocol and PAD dialer

sources-request at mirror.UUCP sources-request at mirror.UUCP
Tue Feb 10 04:04:10 AEST 1987


Submitted by: seismo!mnetor!spectrix!clewis
Mod.sources: Volume 8, Issue 50
Archive-name: uucp.x25pad

[  A Makefile and manpage wouldn't be sensible for this posting.
   I haven't tested this code; heck, it usually takes strong medicine
   to get me to even _look_ at UUCP code.  Still and all, this may
   be useful, given the recent increase in net interest in writing
   a public-domain UUCP.  --r$  ]

I mentioned on the net that I had written a PAD dialer for UUCP, and
I've had a fair number of requests for it.  I spoke to Rick Adams about
it, and he said that I can post it along with the "f" protocol source
itself.
	-Chris Lewis

#!/bin/sh
echo 'Start of pack.out, part 01 of 01:'
echo 'x - READMEfio'
sed 's/^X//' > READMEfio << '/'
X			F protocol (X.25 PAD)
X			Installation hints
X
X"F" protocol is a UUCP protocol used to communicate over X.25 networks.
XThe PAD dialer is a "real" dialer that can be used to set up connections
Xto remote X.25 destinations using MICOM or Motorola PADS - and will probably
Xwork with most other PADS.  fio.c was originally distributed with various 
X"alpha-test" versions of the UUCP in BSD4.3 and has been posted several
Xtimes.  I wrote the PAD dialer.  This readme gives some pointers on how 
Xto install this into your UUCP.
X
XApplicability: if you already have "f" protocol (eg: you already have BSD4.3 
XUUCP), fio.c is likely to be a little older than the one you have, so don't 
Xbother using it.  However, Rick Adams has told me that the PAD dialer 
Xdidn't make it into real BSD4.3, so the dialer should be really useful to you
Xwithout any changes.  If you have an older UUCP (eg: BSD4.2 or previous, 
XSystem V, XENIX) you may be able to install both of these files.
X
XNote: I have never tried to install either of these into non-4.3 UUCP,
Xso your mileage may vary - greatly.  The pad dialer in particular makes use
Xof "generic" facilities (ABORT sequences, chat scripts etc.) that are not
Xlikely to be accessible in older UUCPs.  So you may have to do some carving
Xjust to get your new UUCP to compile and link.  I'm afraid you're on your
Xown in that case.
X
XInstallation:
X	1) Make copies of cntrl.c and condevs.c
X	2) Insert into cntrl.c, near the beginning:
X	    #ifdef PAD
X	    extern int fturnon(), fturnoff();
X	    extern int frdmsg(), frddata();
X	    extern int fwrmsg(), fwrdata();
X	    #endif PAD
X	3) in cntrl.c, inside the "struct Proto Ptbl[] =" initialization,
X	   insert the following just before the "g" proto definition:
X	    #ifdef PAD
X		'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff,
X	    #endif PAD
X	4) In cntrl.c, inside the fptcl(str) function,
X	   you will see something like:
X	    for (p = Ptbl; p->P_id != '\0'; p++) {
X	    ...
X		if (index(str, p->P_id) != NULL) {
X			return p->P_id;
X		}
X	    }
X	   Insert the following code just before the "index" line:
X	    #ifdef PAD
X		/* only use 'f' protocol on PAD */
X		if (p->P_id == 'f' && strcmp("PAD", Flds[F_LINE]))
X			continue;
X	    #endif PAD
X	
X	5) in condevs.c, insert the following into the 
X	   "struct condev condevs[]=" initialization:
X	    #ifdef PAD
X		{ "PAD", "PAD", padopn, nulldev, padcls },
X	    #endif
X	6) insert "#define PAD 1" into your uucp.h
X	7) copy pad.c into the directory containing the rest of the dialers
X	   and modify the makefile to compile it.
X	8) copy fio.c into the main UUCP directory and modify the makefile
X	   to compile it.
X	9) run your UUCP make.
X
XYou may encounter a number of undefined things.  If "dochat" is undefined,
Xremove it from pad.c.  Ditto the stuff about ABORT sequences.
X
XTypical L.sys entry:
X
X<system> Any PAD <speed> <seq> 
X
XWhere <speed> is the baud rate between your computer and your pad.  <seq>
Xis the "dial number" to dial the destination.  Eg: if you have to type
X"c 12345555" to reach that destination, place "12345555" here.  You may
Xencounter length restrictions when talking to the PAD, so you may have to
Xset up "2-character aliases" in the PAD configuration.
X
XTypical L-devices entry:
X
XPAD <tty> ignored <baud> <chat sequence>
X
XThe <baud> must be the same as in the L.sys entry.  <tty> is the ttyname
Xthat the PAD is connected to.  Eg: "tty44".  Chat sequence (alternatively
Xprotocol specification in some versions of SV UUCP) is probably not
Xof any use unless you have the rest of 4.3BSD UUCP.  Duplicate this line
Xwith "DIR" instead of "PAD" so that you can "cu" to the line.
X
XOther setup: on dialer out-going line: disable getty, and connect the line
Xto the PAD.  Initialize the PAD line parameters so that it is a "outgoing"
Xport, and that you can get at X.28 command mode.  Eg: you should be able
Xto "cu" to the line and dial out using X.28 commands.  Do not worry about
Xany other parameters because the dialer will initialize all of the parameters
Xon the line every time it starts up, and when the link is broken, the parameters
Xrevert.  Thus, the best thing to do is initialize the line for outgoing
Xcu.
/
echo 'x - pad.c'
sed 's/^X//' > pad.c << '/'
X
X#ifndef lint
Xstatic char	*RcsId = "$Header: pad.c,v 1.1 85/01/08 19:58:45 rick Exp $";
X#endif !lint
X
X#include "../condevs.h"
X#ifdef PAD
X
X/*
X *	padopn: establish connection through a PAD.
X *	Returns descriptor open to tty for reading and writing.
X *	Negative values (-1...-7) denote errors in connmsg.
X *	Be sure to disconnect tty when done, via HUPCL or stty 0.
X */
X
Xchar *padparms[] = {
X	"set1:0,2:0,3:2,4:1,5:1,6:5,7:4,9:0,10:0,13:0",
X	"set14:0,15:0,16:0,17:0,18:0,19:1,20:255",
X	"set102:0,103:17,104:19,105:0,106:0,107:0,108:0",
X	"set109:0,110:0,111:0,112:0,113:0,114:0,115:0,116:0",
X	NULL
X};
X
Xextern	char	*AbortOn;
Xint	padcls();
Xpadopn(flds)
Xregister char *flds[];
X{
X	char phone[MAXPH+1];
X	register char **parmptr;
X	extern errno;
X	char *rindex(), *fdig(), dcname[20];
X	int dh, ok = 0, speed;
X	register struct condev *cd;
X	register FILE *dfp;
X	struct Devices dev;
X
X	dfp = fopen(DEVFILE, "r");
X	ASSERT(dfp != NULL, "Can't open", DEVFILE, 0);
X
X	signal(SIGALRM, alarmtr);
X	dh = -1;
X	for(cd = condevs; ((cd->CU_meth != NULL)&&(dh < 0)); cd++) {
X		if (snccmp(flds[F_LINE], cd->CU_meth) == SAME) {
X			fseek(dfp, (off_t)0, 0);
X			while(rddev(dfp, &dev) != FAIL) {
X				if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
X					continue;
X				if (snccmp(flds[F_LINE], dev.D_type) != SAME)
X					continue;
X				DEBUG(4, "Trying line %s\n", dev.D_line);
X				if (mlock(dev.D_line) == FAIL)
X					continue;
X
X				sprintf(dcname, "/dev/%s", dev.D_line);
X				getnextfd();
X				alarm(10);
X				if (setjmp(Sjbuf)) {
X					delock(dev.D_line);
X					logent(dev.D_line,"pad open TIMEOUT");
X					dh = -1;
X					break;
X				}
X				dh = open(dcname, 2);
X				alarm(0);
X				next_fd = -1;
X				if (dh > 0) {
X					break;
X				}
X				DEBUG(4, "Can't open line %s\n", dev.D_line);
X				devSel[0] = '\0';
X				delock(dev.D_line);
X			}
X		}
X	}
X	fclose(dfp);
X	if (dh < 0)
X		return CF_NODEV;
X	DEBUG(4, "Using line %s\n", dev.D_line);
X
X	speed = atoi(fdig(flds[F_CLASS]));
X	fixline(dh, speed);
X	/*	Do we need this?  I don't know	*/
X	sleep(1);
X
X	/* Synchronize with PAD prompt */
X	write(dh, "\r", 1);
X	DEBUG(10, "Pad Sync: wanted %s\n", ">");
X	ok = expect(">", dh);
X	DEBUG(10, "got %s\n", ok ? "?" : "that");
X
X	if (ok) {
X		logent(dev.D_line, "PAD SYNC FAILED");
X		close(dh);
X		return CF_DIAL;
X	}
X
X	/*	Initialization of PAD	*/
X	AbortOn = "err";
X	for (parmptr = padparms; ok == 0 && *parmptr; parmptr++) {
X		DEBUG(10, "PAD setup: %s\n", *parmptr);
X		write(dh, *parmptr, strlen(*parmptr));
X		write(dh, "\r", 1);
X		ok = expect(">", dh);
X		DEBUG(4, "setup %s\n", ok? "failed": "worked");
X	}
X	if (Debug > 10) {
X		DEBUG(10, "PAD %s:\n", "configuration");
X		write(dh, "par?\r", 6);
X		ok = expect(">", dh);
X	}
X	AbortOn = NULL;		/* dochat(login) does this anyways */
X	if (ok) {
X		logent(dev.D_line, "PAD SETUP/CONFIG DEBUG FAILED");
X		close(dh);
X		return CF_DIAL;
X	}
X
X	/*	Do chat from L-devices */
X	if (dochat(&dev, flds, dh)) {
X		logent(dev.D_line, "CHAT FAILED");
X		close(dh);
X		return CF_DIAL;
X	}
X
X	if (ok == 0) {
X		exphone(flds[F_PHONE], phone);
X		DEBUG(4, "PAD: calling %s\n", phone);
X		write(dh, "c ", 2);
X		write(dh, phone, strlen(phone));
X		write(dh, "\r", 1);
X		DEBUG(4, "wanted %s ", "com");
X		AbortOn = "clr";
X		ok = expect("com", dh);
X		DEBUG(4, "got %s\n", ok ? "?" : "that");
X		AbortOn = NULL;
X	}
X
X	if (ok != 0) {
X		if (dh > 2)
X			close(dh);
X		DEBUG(4, "pad failed\n", "");
X		delock(dev.D_line);
X		return(CF_DIAL);
X	} 
X	else
X		DEBUG(4, "pad ok\n", "");
X
X	CU_end = padcls;
X	strcat(devSel, dev.D_line);	/* for later unlock */
X	return dh;
X}
X
Xpadcls(fd)
Xregister int fd;
X{
X
X	if (fd > 0) {
X		DEBUG(4, "Closing %s\n", "PAD");
X		close(fd);
X		delock(devSel);
X	}
X}
X#endif MICOM
/
echo 'x - fio.c'
sed 's/^X//' > fio.c << '/'
X/* $Header: fio.c,v 1.20 85/04/30 12:57:32 rick Exp $ */
X/*	%M%	%I%	%E%	(Mathematisch Centrum)	*/
X
X/*
X * flow control protocol.
X *
X * This protocol relies on flow control of the data stream.
X * It is meant for working over links that can (almost) be
X * guaranteed to be errorfree, specifically X.25/PAD links.
X * A sumcheck is carried out over a whole file only. If a
X * transport fails the receiver can request retransmission(s).
X * This protocol uses a 7-bit datapath only, so it can be
X * used on links that are not 8-bit transparent.
X *
X * When using this protocol with an X.25 PAD:
X * Although this protocol uses no control chars except CR,
X * control chars NULL and ^P are used before this protocol
X * is started; since ^P is the default char for accessing
X * PAD X.28 command mode, be sure to disable that access
X * (PAD par 1). Also make sure both flow control pars
X * (5 and 12) are set. The CR used in this proto is meant
X * to trigger packet transmission, hence par 3 should be 
X * set to 2; a good value for the Idle Timer (par 4) is 10.
X * All other pars should be set to 0.
X * Normally a calling site will take care of setting the
X * local PAD pars via an X.28 command and those of the remote
X * PAD via an X.29 command, unless the remote site has a
X * special channel assigned for this protocol with the proper
X * par settings.
X *
X * Author: Piet Beertema, CWI, Amsterdam, Sep 1984
X */
X
X#include "uucp.h"
X#include <signal.h>
X#ifdef USG
X#include <termio.h>
X#else !USG
X#include <sgtty.h>
X#endif !USG
X#include <setjmp.h>
X
X#define FBUFSIZ		256
X
X#ifndef MAXMSGLEN
X#define MAXMSGLEN	BUFSIZ
X#endif MAXMSGLEN
X
Xstatic int chksum;
Xstatic jmp_buf Ffailbuf;
X
Xstatic
Xfalarm()
X{
X	signal(SIGALRM, falarm);
X	longjmp(Ffailbuf, 1);
X}
X
Xstatic int (*fsig)();
X
X#ifndef USG
X#define TCGETA	TIOCGETP
X#define TCSETAF	TIOCSETP
X#define termio	sgttyb
X#else
X#endif USG
X
Xfturnon()
X{
X	int ret;
X	struct termio ttbuf;
X
X	ioctl(Ifn, TCGETA, &ttbuf);
X#ifdef USG
X	ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
X	ttbuf.c_cc[VMIN] = FBUFSIZ > 64 ? 64 : FBUFSIZ;
X	ttbuf.c_cc[VTIME] = 5;
X#else
X	ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
X#endif USG
X	ret = ioctl(Ifn, TCSETAF, &ttbuf);
X	ASSERT(ret >= 0, "STTY FAILED", "", ret);
X#ifndef	USG
X	{
X	    int	localmodeword;
X	    ioctl(Ifn, TIOCLGET, &localmodeword);
X	    DEBUG(8, "local mode word: %o\n", localmodeword);
X	    localmodeword &= ~LNOHANG;
X	    ioctl(Ifn, TIOCLSET, &localmodeword);
X	}
X#endif
X	fsig = signal(SIGALRM, falarm);
X	/* give the other side time to perform its ioctl;
X	 * otherwise it may flush out the first data this
X	 * side is about to send.
X	 */
X	sleep(2);
X	return SUCCESS;
X}
X
Xfturnoff()
X{
X	(void) signal(SIGALRM, fsig);
X	return SUCCESS;
X}
X
Xfwrmsg(type, str, fn)
Xregister char *str;
Xint fn;
Xchar type;
X{
X	register char *s;
X	char bufr[MAXMSGLEN];
X
X	s = bufr;
X	*s++ = type;
X	while (*str)
X		*s++ = *str++;
X	if (*(s-1) == '\n')
X		s--;
X	*s++ = '\r';
X	(void) write(fn, bufr, s - bufr);
X	return SUCCESS;
X}
X
Xfrdmsg(str, fn)
Xregister char *str;
Xregister int fn;
X{
X	register char *smax;
X
X	if (setjmp(Ffailbuf))
X		return FAIL;
X	smax = str + MAXMSGLEN - 1;
X	(void) alarm(2*MAXMSGTIME);
X	for (;;) {
X		if (read(fn, str, 1) <= 0)
X			goto msgerr;
X		if (*str == '\r')
X			break;
X		if (*str < ' ')
X			continue;
X		if (str++ >= smax)
X			goto msgerr;
X	}
X	*str = '\0';
X	(void) alarm(0);
X	return SUCCESS;
Xmsgerr:
X	(void) alarm(0);
X	return FAIL;
X}
X
Xfwrdata(fp1, fn)
XFILE *fp1;
Xint fn;
X{
X	register int flen, alen, ret;
X	register char *obp;
X	char ibuf[FBUFSIZ];
X	char ack;
X	long abytes, fbytes;
X	struct timeb t1, t2;
X	int mil, retries = 0;
X
X	ret = FAIL;
Xretry:
X	chksum = 0xffff;
X	abytes = fbytes = 0L;
X	ack = '\0';
X#ifdef USG
X	time(&t1.time);
X	t1.millitm = 0;
X#else !USG
X	ftime(&t1);
X#endif !USG
X	while ((flen = fread(ibuf, sizeof (char), FBUFSIZ, fp1)) > 0) {
X		alen = fwrblk(fn, ibuf, flen);
X		abytes += alen >= 0 ? alen : -alen;
X		if (alen <= 0)
X			goto acct;
X		fbytes += flen;
X	}
X	sprintf(ibuf, "\176\176%04x\r", chksum);
X	abytes += alen = strlen(ibuf);
X	if (write(fn, ibuf, alen) == alen) {
X		DEBUG(8, "wrdata: checksum length: %d\n", alen);
X		DEBUG(8, "checksum: %04x\n", chksum);
X		if (frdmsg(ibuf, fn) != FAIL) {
X			if ((ack = ibuf[0]) == 'G')
X				ret = 0;
X			DEBUG(4, "ack - '%c'\n", ack);
X		}
X	}
Xacct:
X	if (ack == 'R') {
X		DEBUG(4, "RETRY:\n", 0);
X		fseek(fp1, 0L, 0);
X		retries++;
X		goto retry;
X	}
X#ifdef USG
X	time(&t2.time);
X	t2.millitm = 0;
X#else !USG
X	ftime(&t2);
X#endif !USG
X	Now = t2;
X	t2.time -= t1.time;
X	mil = t2.millitm - t1.millitm;
X	if (mil < 0) {
X		--t2.time;
X		mil += 1000;
X	}
X	sprintf(ibuf, "sent data %ld bytes %ld.%02d secs",
X				fbytes, (long)t2.time, mil/10);
X	sysacct(abytes, t2.time - t1.time);
X	if (retries > 0) 
X		sprintf((char *)ibuf+strlen(ibuf)," %d retries", retries);
X	DEBUG(1, "%s\n", ibuf);
X	syslog(ibuf);
X#ifdef SYSACCT
X	if (ret)
X		sysaccf(NULL);		/* force accounting */
X#endif SYSACCT
X	return ret;
X}
X
X/* max. attempts to retransmit a file: */
X#define MAXRETRIES	(fbytes < 10000L ? 2 : 1)
X
Xfrddata(fn, fp2)
Xregister int fn;
Xregister FILE *fp2;
X{
X	register int flen;
X	register char eof;
X	char ibuf[FBUFSIZ];
X	int ret, retries = 0;
X	long alen, abytes, fbytes;
X	struct timeb t1, t2;
X	int mil;
X
X	ret = FAIL;
Xretry:
X	chksum = 0xffff;
X	abytes = fbytes = 0L;
X#ifdef USG
X	time(&t1.time);
X	t1.millitm = 0;
X#else !USG
X	ftime(&t1);
X#endif !USG
X	do {
X		flen = frdblk(ibuf, fn, &alen);
X		abytes += alen;
X		if (flen < 0)
X			goto acct;
X		if (eof = flen > FBUFSIZ)
X			flen -= FBUFSIZ + 1;
X		fbytes += flen;
X		if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
X			goto acct;
X	} while (!eof);
X	ret = 0;
Xacct:
X	if (ret) {
X		if (retries++ < MAXRETRIES) {
X			DEBUG(8, "send ack: 'R'\n", 0);
X			fwrmsg('R', "", fn);
X			fseek(fp2, 0L, 0);
X			DEBUG(4, "RETRY:\n", 0);
X			goto retry;
X		}
X		DEBUG(8, "send ack: 'Q'\n", 0);
X		fwrmsg('Q', "", fn);
X#ifdef SYSACCT
X		sysaccf(NULL);		/* force accounting */
X#endif SYSACCT
X	} else {
X		DEBUG(8, "send ack: 'G'\n", 0);
X		fwrmsg('G', "", fn);
X	}
X#ifdef USG
X	time(&t2.time);
X	t2.millitm = 0;
X#else !USG
X	ftime(&t2);
X#endif !USG
X	Now = t2;
X	t2.time -= t1.time;
X	mil = t2.millitm - t1.millitm;
X	if (mil < 0) {
X		--t2.time;
X		mil += 1000;
X	}
X	sprintf(ibuf, "received data %ld bytes %ld.%02d secs",
X				fbytes, (long)t2.time, mil/10);
X	sysacct(abytes, t2.time - t1.time);
X	if (retries > 0) 
X		sprintf((char *)ibuf+strlen(ibuf)," %d retries", retries);
X	DEBUG(1, "%s\n", ibuf);
X	syslog(ibuf);
X	return ret;
X}
X
Xstatic
Xfrdbuf(blk, len, fn)
Xregister char *blk;
Xregister int len;
Xregister int fn;
X{
X	static int ret = FBUFSIZ / 2;
X#ifndef Not080
X	extern int linebaudrate;
X#endif Not080
X
X	if (setjmp(Ffailbuf))
X		return FAIL;
X#ifndef Not080
X	if (len == FBUFSIZ && ret < FBUFSIZ / 2 &&
X	    linebaudrate > 0 && linebaudrate < 4800)
X		sleep(1);
X#endif Not080
X	(void) alarm(MAXMSGTIME);
X	ret = read(fn, blk, len);
X	alarm(0);
X	return ret <= 0 ? FAIL : ret;
X}
X
X/* call ultouch every TC calls to either frdblk or fwrblk  */
X
X#define	TC	20
Xstatic	int tc = TC;
X
X/* Byte conversion:
X *
X *   from        pre       to
X * 000-037       172     100-137
X * 040-171               040-171
X * 172-177       173     072-077
X * 200-237       174     100-137
X * 240-371       175     040-171
X * 372-377       176     072-077
X */
X
Xstatic
Xfwrblk(fn, ip, len)
Xint fn;
Xregister char *ip;
Xregister int len;
X{
X	register char *op;
X	register int sum, nl;
X	int ret;
X	char obuf[FBUFSIZ * 2];
X
X	/* call ultouch occasionally */
X	if (--tc < 0) {
X		tc = TC;
X		ultouch();
X	}
X	DEBUG(8, "fwrblk: %d/", len);
X	op = obuf;
X	nl = 0;
X	sum = chksum;
X	do {
X		if (sum & 0x8000) {
X			sum <<= 1;
X			sum++;
X		} else
X			sum <<= 1;
X		sum += *ip & 0377;
X		sum &= 0xffff;
X		if (*ip & 0200) {
X			*ip &= 0177;
X			if (*ip < 040) {
X				*op++ = '\174';
X				*op++ = *ip++ + 0100;
X			} else
X			if (*ip <= 0171) {
X				*op++ = '\175';
X				*op++ = *ip++;
X			}
X			else {
X				*op++ = '\176';
X				*op++ = *ip++ - 0100;
X			}
X			nl += 2;
X		} else {
X			if (*ip < 040) {
X				*op++ = '\172';
X				*op++ = *ip++ + 0100;
X				nl += 2;
X			} else
X			if (*ip <= 0171) {
X				*op++ = *ip++;
X				nl++;
X			} else {
X				*op++ = '\173';
X				*op++ = *ip++ - 0100;
X				nl += 2;
X			}
X		}
X	} while (--len);
X	chksum = sum;
X	DEBUG(8, "%d\n", nl);
X	ret = write(fn, obuf, nl);
X	return ret == nl ? nl : ret < 0 ? 0 : -ret;
X}
X
Xstatic
Xfrdblk(ip, fn, rlen)
Xregister char *ip;
Xint fn;
Xlong *rlen;
X{
X	register char *op, c;
X	register int sum, len, nl;
X	char buf[5], *erbp = ip;
X	int i;
X	static char special = 0;
X
X	/* call ultouch occasionally */
X	if (--tc < 0) {
X		tc = TC;
X		ultouch();
X	}
X
X	if ((len = frdbuf(ip, FBUFSIZ, fn)) == FAIL) {
X		*rlen = 0;
X		goto dcorr;
X	}
X	*rlen = len;
X	DEBUG(8, "%d/", len);
X	op = ip;
X	nl = 0;
X	sum = chksum;
X	do {
X		if ((*ip &= 0177) >= '\172') {
X			if (special) {
X				DEBUG(8, "%d", nl);
X				special = 0;
X				op = buf;
X				if (*ip++ != '\176' || (i = --len) > 5)
X					goto dcorr;
X				while (i--)
X					*op++ = *ip++;
X				while (len < 5) {
X					i = frdbuf(&buf[len], 5 - len, fn);
X					if (i == FAIL) {
X						len = FAIL;
X						goto dcorr;
X					}
X					DEBUG(8, ",%d", i);
X					len += i;
X					*rlen += i;
X				}
X				if (buf[4] != '\r')
X					goto dcorr;
X				sscanf(buf, "%4x", &chksum);
X				DEBUG(8, "\nchecksum: %04x\n", sum);
X				if (chksum == sum)
X					return FBUFSIZ + 1 + nl;
X				else {
X					DEBUG(8, "\n", 0);
X					DEBUG(4, "Bad checksum\n", 0);
X					return FAIL;
X				}
X			}
X			special = *ip++;
X		} else {
X			if (*ip < '\040') {
X				/* error: shouldn't get control chars */
X				goto dcorr;
X			}
X			switch (special) {
X			case 0:
X				c = *ip++;
X				break;
X			case '\172':
X				c = *ip++ - 0100;
X				break;
X			case '\173':
X				c = *ip++ + 0100;
X				break;
X			case '\174':
X				c = *ip++ + 0100;
X				break;
X			case '\175':
X				c = *ip++ + 0200;
X				break;
X			case '\176':
X				c = *ip++ + 0300;
X				break;
X			}
X			*op++ = c;
X			if (sum & 0x8000) {
X				sum <<= 1;
X				sum++;
X			} else
X				sum <<= 1;
X			sum += c & 0377;
X			sum &= 0xffff;
X			special = 0;
X			nl++;
X		}
X	} while (--len);
X	chksum = sum;
X	DEBUG(8, "%d,", nl);
X	return nl;
Xdcorr:
X	DEBUG(8, "\n", 0);
X	DEBUG(4, "Data corrupted\n", 0);
X	while (len != FAIL) {
X		if ((len = frdbuf(erbp, FBUFSIZ, fn)) != FAIL)
X			*rlen += len;
X	}
X	return FAIL;
X}
/
echo 'Part 01 of pack.out complete.'
exit



More information about the Mod.sources mailing list