[comp.binaries.ibm.pc] Xmodem/ymodem/modem7 for 4.2/4.3 BSD Unix, part 1of2

w8sdz@brl-smoke.ARPA (Keith B. Petersen ) (05/03/88)

This is version 3.6 (finished 4/88) of Steve Grandi's 4.2/4.3 BSD Unix
xmodem program which includes a few bugfixes and some enhancements
(requested by Macintosh users) stimulated by the xmodem release through
comp.sources.unix.  See the file update.doc for details.

---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.20)
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  README
#	  batch.c
#	  getput.c
#	  getput.sysv.c
#	  misc.c
#	  receive.c
#	  send.c
#	  tip.diffs
#	  update.doc
#	  xmodem.1
#	  xmodem.c
#	  xmodem.h
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
XOBJECTS = xmodem.o getput.o misc.o send.o receive.o batch.o
XCFLAGS = -O
X
Xxmodem: $(OBJECTS)
X	cc $(CFLAGS) $(OBJECTS) -o xmodem
X
X$(OBJECTS): xmodem.h
X
Xprint: 
X	lpr -p -Pvmslp xmodem.h xmodem.c getput.c receive.c send.c batch.c \
X	misc.c Makefile update.doc README xmodem.1 getput.sysv.c
X
Xlint:
X	lint xmodem.c getput.c receive.c send.c batch.c misc.c | imprint
X
Xshar:
X	shar README update.doc Makefile xmodem.1 xmodem.h > xmodem.shar.1
X	shar xmodem.c receive.c misc.c > xmodem.shar.2
X	shar getput.c getput.sysv.c > xmodem.shar.3
X	shar batch.c send.c > xmodem.shar.4
X	shar tip.diffs > xmodem.shar.5
X
Xbigshar: 
X	shar README update.doc Makefile xmodem.1 xmodem.h xmodem.c getput.c \
X	getput.sysv.c receive.c misc.c batch.c send.c tip.diffs > xmodem.shar
X
Xtarz: 
X	tar cvf xmodem.tar README update.doc Makefile xmodem.1 xmodem.h \
X	xmodem.c getput.c getput.sysv.c receive.c misc.c batch.c send.c \
X	tip.diffs ymodem.doc
X	compress xmodem.tar
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XThis is version 3.6 (finished 4/88) of the xmodem program which includes a
Xfew bugfixes and some enhancements (requested by Macintosh users)
Xstimulated by the xmodem release through comp.sources.unix.  See the file
Xupdate.doc for details. 
X
X--------------------------------------------------------------------------------
X
XThis is version 3.4 (finished 10/87) of the xmodem program, a full-featured
XXMODEM implementation for 4.3BSD.  Since the previous release (version
X3.2, see volume 7 of the archives), substantial improvements have been
Xmade. See the file update.doc for details.  Also, some attempt has been
Xmade to support SysV Unix systems; see below.
X
XAs far as I am concerned, this program has reached the end of its evolution.
XNewer protocols (such as ZMODEM) will not be incorporated into xmodem.  Check
Xout Chuck Forsberg's rz/sz programs if you are interested in ZMODEM.
X
XTo answer one oft-asked question: No, I don't know how to tie this
Xfull-featured xmodem program into tip or cu for file transfers when calling
Xout from a 4.3BSD system.  4.3BSD tip does have some undocumented hooks
Xfor tying into other programs through redirecting file descriptors, but my
Xminimal attempts to utilize these hooks have failed.  However, several
Xyears back, I built a VERY early version of xmodem (lacking XMODEM/CRC,
XXMODEM-1K, MODEM7 batch or YMODEM) directly into 4.2BSD tip.  The changes
Xworked unmodified in 4.3BSD; the diff files are contained in the file
Xtip.diffs.
X
X--------------------------------------------------------------------------------
X
XThe xmodem program implements the Christensen (XMODEM) file transfer
Xprotocol for moving files between 4.2/4.3BSD Unix systems and microcomputers.
XThe XMODEM/CRC protocol, the MODEM7 batch protocol, the XMODEM-1K
Xblock protocol and the YMODEM batch protocol are all supported by xmodem.
XFor details of the protocols, see the document edited by Chuck Forsberg titled
XXMODEM/YMODEM Protocol Reference (the latest version is dated 8-4-87).
X
XThis program runs on 4.2/4.3BSD systems ONLY.  It has been tested on VAXes
Xand Suns against the MEX-PC program from Niteowl Software and the ZCOMM and
XDSZ programs from Omen Technology.
X
XI have tried to keep the 4.2isms (select system call, 4.2BSD/v7 tty structures,
Xgettimeofday system call, etc.) confined to the source file getput.c; but I 
Xmake no guarantees.  Also, I have made no attempt to keep variable names 
Xunder 7 characters.  A version of getput.c that MAY work on Sys V Unix
Xsystems is included.
X
X--------------------------------------------------------------------------------
X
XThanks to Emmet Gray (ihnp4!uiucuxc!fthood!egray) and John Rupley 
X(arizona!rupley!root) for the following notes about converting xmodem to Sys V.
XSince I don't have a Sys V system to test a Sys V version, I won't even try.
X
X1) Change the includes in xmodem.h from <sys/time.h> to <time.h>
X   and from <sgtty.h> to <termio.h>
X
X2) Convert the occurrences of rindex to strrchr in batch.c
X
X3) Substitute getput.sysv.c for getput.c
X
X--------------------------------------------------------------------------------
X
XProgram history:
X
XDescended from UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
X
XBased on XMODEM Version 1.0 by Brian Kantor, UCSD (3/84)  (Don't blame him 
Xfor what follows....)
X
XVersion 2.0 (CRC-16 and Modem7 batch file transfer) (5/85)
X
XVersion 2.1 (1K packets) (7/85)
X
XVersion 2.2 (general clean-ups and multi-character read speed-ups) (9/85)
X
XVersion 2.3 (nap while reading packets; split into several source files) (1/86)
X
XVersion 3.0 (Ymodem batch receive; associated changes) (2/86)
X
XVersion 3.1 (Ymodem batch send; associated changes) (8/86)
X
XVersion 3.2 (general cleanups) (9/86) 
X    (Released to the world 1/87)
X
XVersion 3.3 (general fixes and cleanups; see update.doc) (5/87)
X
XVersion 3.4 (general fixes and cleanups; see update.doc) (10/87) 
X    (Released to the world 3/88)
X
XVersion 3.5 (general fixes and cleanups; see update.doc) (3/88)
X
XVersion 3.6 (general fixes and cleanups; text file translation for Mac; 
X    see update.doc) (4/88) 
X    (Released to the world 4/88)
X
X--------------------------------------------------------------------------------
X
XPlease send bug fixes, additions and comments to:
XSteve Grandi, National Optical Astronomy Observatories (Tucson, Arizona)
X	{ihnp4,ncar,arizona,...}!noao!grandi  grandi@noao.arizona.edu
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
echo "x - extracting batch.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > batch.c &&
X/*
X *  Various routines for batch transfer
X */
X
X#include "xmodem.h"
X
X/* make sure filename sent or received in YMODEM batch is canonical. */
X
X/* Incoming: Turn Unix '/' into CP/M ':' and translate to all lower case.
X * Remove trailing dot.
X */
X
Xunixify (name)
Xchar *name;
X	{
X	char *ptr;
X
X	/* change '/' to ':' and convert to lower case */
X	for (ptr=name; *ptr; ++ptr)
X		{
X		if (*ptr == '/')
X			*ptr = ':';
X		if (isupper (*ptr))
X			*ptr |= 040;
X		}
X
X	/* remove trailing dot if present */
X	ptr--;
X	if (*ptr == '.')
X		*ptr = '\0';
X	}
X
X/* make sure filename sent or received in YMODEM batch is canonical. */
X
X/* Outgoing: Turn ':' into '/' (for symmetry!) and turn into all lower case.
X * Remove everything before last '/'.  Use "filename" to hold final name.
X */
X
Xchar *
Xcpmify (name)
Xchar *name;
X	{
X	char *ptr, *slash;
X	char *strcpy();
X
X	/* find last '/' and copy rest of name */
X
X	slash = name;
X	for (ptr=name; *ptr; ++ptr)
X		if (*ptr == '/')
X			slash = ptr + 1;
X	strcpy (filename, slash);
X
X	/* change ':' to '/' and covert to all lower case */
X
X	for (ptr=filename; *ptr; ++ptr)
X		{
X		if (*ptr == ':')
X			*ptr = '/';
X		if (isupper (*ptr))
X			*ptr |= 040;
X		}
X	return (filename);
X	}
X
X
X/* convert a CP/M file name received in a MODEM7 batch transfer
X * into a unix file name mapping '/' into ':', converting to all
X * upper case and adding dot in proper place.  
X * Use "filename" to hold name.
X * Code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xchar *
Xcpm_unix (string)
Xunsigned char *string;
X{
X	register int i;
X	unsigned char *iptr, temp;
X	register char *optr;
X
X	if (*string == '\0')
X		error("Null file name in MODEM7 batch receive", TRUE);
X
X	for (iptr=string; (temp = *iptr) ; ) {
X		temp &= 0177;			/* strips bit 7 */
X		if (isupper(temp))
X			temp |= 040;		/* set bit 5 for lower case */
X		if (temp == '/') 
X			temp=':';		/* map / into : */
X		*iptr++ = temp;
X	}
X
X	/* put in main part of name */
X	iptr=string;
X	optr=filename;
X	for (i=0; i<8; i++) {
X		if (*iptr != ' ')
X			*optr++ = *iptr++;
X	}
X
X	/* add dot if necessary */
X	if (string[8] != ' ' || string[9] != ' ' || string[10] != ' ')
X		*optr++ = '.';
X
X	/* put in extension */
X	iptr = &string[8];
X	for (i=0; i<3; i++) {
X		if (*iptr != ' ')
X			*optr++ = *iptr++;
X	}
X
X	*optr++ = '\000';
X	return (filename);
X}
X
X/* Send 11 character CP/M filename for MODEM7 batch transmission
X * Returns -1 for a protocol error; 0 if successful
X * NOTE: we tromp a little on the argument string!
X * code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xsend_name(name)
Xchar *name;
X{
X	register int cksum;
X	register char *ptr;
X
X	xmdebug("send_name");
X
X	/* append cp/m EOF */
X	name[NAMSIZ] = CTRLZ;
X	name[NAMSIZ+1] = '\000';
X
X	/* create checksum */
X	ptr = name;
X	cksum = 0;
X	while (*ptr)
X		cksum += *ptr++;
X	cksum &= 0x00FF;
X
X	/* send filename */
X
X	sendbyte(ACK);
X	ptr = name;
X	sendbyte(*ptr++);
X
X	while (*ptr) {
X
X			switch (readbyte(15)) {
X
X			case ACK: break;
X
X			case TIMEOUT: {
X				logit("Timeout while sending MODEM7 filename\n");
X				sendbyte(BAD_NAME);
X				return (-1);
X			}
X
X			default: {
X				logit("Error while sending MODEM7 filename\n");
X				sendbyte(BAD_NAME);
X				return (-1);
X			}
X		}	
X
X		sendbyte (*ptr++);
X	}
X
X	/* Check checksum returned by other side against my value */
X	if (readbyte(16) != cksum) {
X		logit("Bad checksum while sending MODEM7 filename\n");
X		sendbyte(BAD_NAME);
X		return (-1);
X	}
X
X	sendbyte(ACK);
X	return (0);
X}
X
X/* Convert Unix filename to 11 character CP/M file name (8 char name,
X * 3 char extension, dot in between is not included).
X * map ':' into '/'; Use filename to hold name.
X * code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xchar *
Xunix_cpm(string)
Xchar *string;
X{
X	register char *iptr, *optr, temp;
X	int i;
X
X	char *rindex();
X	char *strcpy();
X
X	/* blank 11 character name */
X	(void) strcpy (filename,"           ");
X
X	/* strip off any path name */
X	if ((iptr = rindex(string,'/')))
X		iptr++;
X	else
X		iptr=string;
X
X	/* skip leading '.'s */
X	while (*iptr == '.')
X		iptr++;
X
X	/* copy main part of name */
X	optr = filename;
X	i = 8;
X	while ((i--) && (*iptr) && (*iptr != '.'))
X		*optr++ = *iptr++;
X
X	/* advance to unix extension, or end of unix name */
X	while ((*iptr != '.') && (*iptr))
X		iptr++;
X
X	/* skip over the  '.' */
X	while (*iptr == '.')
X		iptr++;
X
X	/* copy extension */
X	optr = &filename[8];
X	i=3;
X	while ((i--) && (*iptr) && (*iptr != '.'))
X		*optr++ = *iptr++;
X
X	filename[NAMSIZ] = '\000';
X
X	/* Fuss with name */
X	for (iptr=filename; (temp = *iptr) ;) {
X		temp &= 0177;			/* strip bit 7 (parity bit) */
X		if (islower(temp))
X			temp &= ~040;		/* make upper case */
X		if (temp == ':')
X			temp ='/';		/* map ':' into '/' */
X		*iptr++ = temp;
X	}
X
X	if (DEBUG)
X		fprintf (LOGFP, "DEBUG: File %s sent as %s\n", string, filename);
X
X	return(filename);
X}
SHAR_EOF
chmod 0644 batch.c || echo "restore of batch.c fails"
echo "x - extracting getput.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > getput.c &&
X/*
X * Contains system routines to get and put bytes, change tty modes, etc
X * Most of the routines are VERY 4.2BSD Specific!!!
X */
X
X#include "xmodem.h"
X
X/*
X *
X *	Get a byte from the specified file.  Buffer the read so we don't
X *	have to use a system call for each character.
X *
X */
Xgetbyte(fildes, ch)				/* Buffered disk read */
Xint fildes;
Xchar *ch;
X
X	{
X	static char buf[BUFSIZ];	/* Remember buffer */
X	static char *bufp = buf;	/* Remember where we are in buffer */
X	
X	if (nbchr == 0)			/* Buffer exausted; read some more */
X		{
X		if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
X			error("File Read Error", TRUE);
X		bufp = buf;		/* Set pointer to start of array */
X		}
X	if (--nbchr >= 0)
X		{
X		*ch = *bufp++;
X		return(0);
X		}
X	else
X		{
X		return(EOF);
X		}
X	}
X
X/* Count the number of newlines in a file so we know the REAL file size */
X
Xlong
Xcountnl(fd)
Xint fd;
X{
X	char buf[BUFSIZ];
X	char *bufp;
X	long nltot = 0;
X	int numchar;
X	long lseek();
X
X	while (numchar = read(fd, buf, BUFSIZ))		/* cycle through file */
X		for (bufp=buf; numchar--; bufp++)
X			if (*bufp == '\n')
X				nltot++;
X
X	(void) lseek (fd, 0l, 0);			/* rewind file */
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: countnl--%ld newlines counted\n", nltot);
X	return (nltot);
X}
X
X/*   CRC-16 constant array...
X     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
X     (ihnp4!umn-cs!hyper!mark)
X*/
X
X/* crctab as calculated by initcrctab() */
Xunsigned short crctab[1<<B] = { 
X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
X    };
X
X/* get a byte from data stream -- timeout if "seconds" elapses */
X/* This routine is VERY 4.2 specific */
X
Xint
Xreadbyte(seconds)
Xint seconds;
X	{
X	int readfd;
X	char c;
X	struct timeval tmout;
X
X	tmout.tv_sec = seconds;
X	tmout.tv_usec = 0;
X
X	readfd = 1<<0;
X
X	if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
X		return(TIMEOUT);
X
X	read(0, &c, 1);
X
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: readbyte %02xh\n", c & 0xff);
X
X	return(c & 0xff);  /* return the char */
X	}
X
X/* flush input stream by reading pending characters */
X
Xflushin()
X	{
X	int readfd;
X	char inbuf[BBUFSIZ];
X	struct timeval tmout;
X
X	/* set up a usec timeout on stdin */
X	tmout.tv_sec = 0;
X	tmout.tv_usec = 1;
X	readfd = 1<<0;
X
X	/* any characters pending?; return if none */
X	if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
X		return;
X
X	/* read the characters to flush them (assume there are fewer than BBUFSIZ */
X	(void) read(0, inbuf, BBUFSIZ);
X	}
X
X/* 
X get a buffer (length bufsize) from data stream -- timeout if "seconds" elapses.
X Read bunches of characters to save system overhead;
X Further process data while kernel is reading stream (calculating "checksum").
X Try to nap long enough so kernel collects 100 characters or so until we wake up
X unless TOOBUSY is set.
X*/
X
X/* This routine is VERY 4.2 specific */
X
Xint
Xreadbuf(bufsize, seconds, tmode, amode, recvsectcnt, checksum, bufctr)
X
Xint bufsize,	/* number of chars to be read */
Xseconds, 	/* timeout period for each read */
Xtmode, 		/* transmission mode: TRUE if text */
Xamode, 		/* transmission mode: TRUE if apple macintosh */
X*checksum, 	/* pointer to checksum value */
X*bufctr;	/* length of actual data string in buffer */
Xlong recvsectcnt;	/* running sector count (128 byte sectors) */
X
X{
X	int readfd;		/* mask for select call */
X	struct timeval tmout;	/* timeout structure for select */
X	int numread;		/* number of chars read */
X	int left;		/* number of chars left to read */
X	int recfin = FALSE;		/* flag that EOF read */
X	char inbuf[BBUFSIZ];	/* buffer for incoming packet */
X	register unsigned char c;	/* character being processed */
X	register unsigned short chksm;	/* working copy of checksum */
X	register int bfctr;	/* working copy of bufctr */
X	int j;			/* loop index */
X	char *sectdisp();
X
X	tmout.tv_sec = seconds;
X	tmout.tv_usec = 0;
X	readfd = 1<<0;
X	chksm = 0;
X	bfctr = 0;
X
X	for (left = bufsize; left > 0;) {
X
X		/* read however many chars are waiting */
X
X		if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
X			return(TIMEOUT);
X
X		numread = read(0, inbuf, left);
X		left -= numread;
X
X		if (DEBUG)
X			fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread);
X
X		/* now process part of packet we just read */
X
X		for (j =  0; j < numread; j++) 
X			{  
X				buff[bfctr] = c = inbuf[j] & 0xff;
X				fileread++;
X
X				if (CRCMODE)  /* CRC */
X					chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
X
X				else        /* checksum */
X		       			chksm = ((chksm+c) & 0xff);
X
X				if (CHECKLENGTH && fileread > filelength)	/* past EOF ? */
X					continue;
X
X				if (tmode) 		/* text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == CR || c == 0)	/* skip CRs and nulls */
X						continue;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			else if (!recfin)	/* don't increment if past EOF */
X						bfctr++;
X					}
X				else if (amode) 	/* Apple macintosh text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == 0)		/* skip nulls */
X						continue;
X					else if (c == CR)	/* translate CR to LF */
X						buff[bfctr] = LF;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			if (!recfin)		/* don't increment if past EOF */
X						bfctr++;
X					}
X				else			/* binary */
X					bfctr++;
X
X		     	}	
X
X		/* go to sleep to save uneeded system calls while kernel
X		   is reading data from serial line; 
X		   fudge constant from 10000 to 9000 to avoid sleeping too long.
X		*/
X		if (left && !TOOBUSY)
X		    napms( (left<SLEEPNUM ? left:SLEEPNUM) * 9000/ttyspeed);
X
X	}
X
X	if (CHECKLENGTH && fileread >= filelength)
X		logitarg("File end from YMODEM length found in sector %s\n",
X		  sectdisp(recvsectcnt,bufsize,1));
X	*checksum = chksm;
X	*bufctr = bfctr;
X	return(0);
X}
X
X/* send a byte to data stream */
X
Xsendbyte(data)
Xchar data;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: sendbyte %02xh\n", data & 0xff);
X
X	if (write(1, &data, 1) != 1)  	/* write the byte (assume it goes NOW; no flushing needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/* send a buffer to data stream */
X
Xwritebuf(buffer, nbytes)
Xchar *buffer;
Xint  nbytes;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: writebuf (%d bytes)\n", nbytes);
X
X	if (write(1, buffer, nbytes) != nbytes)		/* write the buffer (assume no TIOCFLUSH needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/*
X * "nap" for specified time -- VERY 4.2BSD specific
X */
X
Xnapms (milliseconds)
Xint	milliseconds;
X{
X	struct	timeval	timeout;
X	int readfd;
X
X	if (milliseconds == 0)
X		return;
X	if (DEBUG)
X		fprintf (LOGFP, "DEBUG: napping for %d ms\n", milliseconds);
X	timeout.tv_sec = 0;
X	timeout.tv_usec = milliseconds * 1000;
X	readfd = 0;
X
X	(void) select(1, &readfd, (int *)0, (int *)0, &timeout);
X}
X
X 
X/* set and restore tty modes for XMODEM transfers */
X/* These routines are 4.2/v7(?) specific */
X
Xstruct sgttyb ttys, ttysnew;	/* for stty terminal mode calls */
Xstruct stat statbuf;		/* for terminal message on/off control */
X
Xint wason;			/* holds status of tty read write/modes */
Xchar *tty;			/* current tty name */
X
X
Xsetmodes()
X	{
X	char *ttyname();
X
X	int n;
X
X	extern onintr();
X
X	sleep(2);			/* let the output appear */
X	if (ioctl(0,TIOCGETP,&ttys)<0)  /* get tty params [V7] */
X		error("Can't get TTY Parameters", TRUE);
X
X	tty = ttyname(0);  /* identify current tty */
X	
X	ttysnew.sg_ispeed = ttys.sg_ispeed;	/* copy input speed */
X	ttysnew.sg_ospeed = ttys.sg_ospeed;	/* copy input speed */
X	ttysnew.sg_flags |= RAW;	/* set for RAW Mode */
X	ttysnew.sg_flags &= ~ECHO;	/* set for no echoing */
X	ttysnew.sg_flags &= ~TANDEM;	/* turn off flow control */
X
X	/* set new paramters */
X	if (ioctl(0,TIOCSETP,&ttysnew) < 0)
X		error("Can't set new TTY Parameters", TRUE);
X
X	/* Flush characters waiting for read or write */
X	n = 0;
X	if (ioctl(0,TIOCFLUSH,&n) < 0)
X		error("Can't flush terminal queue", TRUE);
X
X	/* get tty status */ 
X	if (stat(tty, &statbuf) < 0)  
X		error("Can't get your TTY Status", TRUE);
X
X	if (statbuf.st_mode & 022)	/* Need to turn messages off */
X		if (chmod(tty, (int)statbuf.st_mode & ~022) < 0)
X			error("Can't change  TTY mode", TRUE);
X		else 
X			wason = TRUE;
X	else 
X		wason = FALSE;
X
X	/* set up signal catcher to restore tty state if we are KILLed */
X
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, onintr);
X	}
X
X/* restore normal tty modes */
X
Xrestoremodes(errcall)
Xint errcall;
X	{
X	if (wason)
X		if (chmod(tty, (int)statbuf.st_mode | 022) < 0)
X			error("Can't change TTY mode", FALSE);
X	if (ioctl(0,TIOCSETP,&ttys) < 0)
X		{ if (!errcall)
X		   error("RESET - Can't restore normal TTY Params", FALSE);
X		else
X		     printf("RESET - Can't restore normal TTY Params\n");
X		}
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, SIG_DFL);
X	return;
X	}
X
X
X
X
X/* signal catcher */
Xonintr()
X	{
X	error("Kill signal; bailing out", TRUE);
X	}
X
X/* create string with a timestamp for log file */
X
Xchar *stamptime()
X{
X	char *asctime();		/* stuff to get timestamp */
X	struct tm *localtime(), *tp;
X	struct timeval tv;
X	struct timezone tz;
X
X	gettimeofday (&tv, &tz);		/* fill in timestamp */
X	tp = localtime ((time_t *)&tv.tv_sec);
X	return(asctime(tp));
X}
X
X
X
X/* get tty speed for time estimates */
X
Xgetspeed()
X	{
X	static int speedtbl[] = {0, 50, 75, 110, 134, 150, 200, 300, 600, 
X	   1200, 1800, 2400, 4800, 9600, 19200, 0};
X	if (ioctl(0,TIOCGETP,&ttys) < 0)	/* get tty structure */
X		error("Can't get TTY parameters", FALSE);
X
X	if (ttys.sg_ispeed >= 0 && ttys.sg_ispeed <= 14)
X		{
X		ttyspeed = speedtbl[ttys.sg_ispeed];
X		logitarg ("Line speed = %d bits per second\n", ttyspeed);
X		}
X	else
X		{
X		ttyspeed = 1200;
X		logit ("Can't determine line speed; assuming 1200 bps\n");
X		}
X	}
SHAR_EOF
chmod 0644 getput.c || echo "restore of getput.c fails"
echo "x - extracting getput.sysv.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > getput.sysv.c &&
X/*
X * Contains system routines to get and put bytes, change tty modes, etc
X * Sys V version.  UNTESTED!!!!!!
X */
X
X#include "xmodem.h"
X
X/*
X *
X *	Get a byte from the specified file.  Buffer the read so we don't
X *	have to use a system call for each character.
X *
X */
Xgetbyte(fildes, ch)				/* Buffered disk read */
Xint fildes;
Xchar *ch;
X
X	{
X	static char buf[BUFSIZ];	/* Remember buffer */
X	static char *bufp = buf;	/* Remember where we are in buffer */
X	
X	if (nbchr == 0)			/* Buffer exausted; read some more */
X		{
X		if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
X			error("File Read Error", TRUE);
X		bufp = buf;		/* Set pointer to start of array */
X		}
X	if (--nbchr >= 0)
X		{
X		*ch = *bufp++;
X		return(0);
X		}
X	else
X		{
X		return(EOF);
X		}
X	}
X
X/* Count the number of newlines in a file so we know the REAL file size */
X
Xlong
Xcountnl(fd)
Xint fd;
X{
X	char buf[BUFSIZ];
X	char *bufp;
X	long nltot = 0;
X	int numchar;
X	long lseek();
X
X	while (numchar = read(fd, buf, BUFSIZ))		/* cycle through file */
X		for (bufp=buf; numchar--; bufp++)
X			if (*bufp == '\n')
X				nltot++;
X
X	(void) lseek (fd, 0l, 0);			/* rewind file */
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: countnl--%ld newlines counted\n", nltot);
X	return (nltot);
X}
X
X/*   CRC-16 constant array...
X     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
X     (ihnp4!umn-cs!hyper!mark)
X*/
X
X/* crctab as calculated by initcrctab() */
Xunsigned short crctab[1<<B] = { 
X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
X    };
X
X/* get a byte from data stream -- timeout if "seconds" elapses */
X
Xint timedout;
X 
Xint
Xreadbyte(seconds)
Xint seconds;
X{
X	int force_it();
X	char c;
X	signal(SIGALRM, force_it);
X
X	timedout = 0;
X	alarm(seconds);
X	read(0, &c, 1);
X	alarm(0);
X	if (timedout)
X		return(TIMEOUT);
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: readbyte %02xh\n", c & 0xff);
X	return(c & 0xff);
X}
X
Xint
Xforce_it()
X{
X	timedout++;
X	return;
X}
X
X
X/* flush input stream */
X
Xflushin()
X	{
X/* No good way to do this without select */
X/* Perhaps....but we waste 1 second with every call!
X	while (readbyte(1) != TIMEOUT)
X		;
X*/
X	}
X
X/* 
X get a buffer (length bufsize) from data stream -- timeout if "seconds" elapses.
X Read bunches of characters to save system overhead;
X Further process data while kernel is reading stream (calculating "checksum").
X Try to nap long enough so kernel collects 100 characters or so until we wake up
X unless TOOBUSY is set.
X*/
X
X
Xint
Xreadbuf(bufsize, seconds, tmode, amode, recvsectcnt, checksum, bufctr)
X
Xint bufsize,	/* number of chars to be read */
Xseconds, 	/* timeout period for each read */
Xtmode, 		/* transmission mode: TRUE if text */
Xamode, 		/* transmission mode: TRUE if apple macintosh */
X*checksum, 	/* pointer to checksum value */
X*bufctr;	/* length of actual data string in buffer */
Xlong recvsectcnt;	/* running sector count (128 byte sectors) */
X
X{
X	int force_it();
X	int numread;		/* number of chars read */
X	int left;		/* number of chars left to read */
X	int recfin = 0;		/* flag that EOF read */
X	char inbuf[BBUFSIZ];	/* buffer for incoming packet */
X	register unsigned char c;	/* character being processed */
X	register unsigned short chksm;	/* working copy of checksum */
X	register int bfctr;	/* working copy of bufctr */
X	int j;			/* loop index */
X	char *sectdisp();
X
X	signal(SIGALRM, force_it);
X	chksm = 0;
X	bfctr = 0;
X
X	for (left = bufsize; left > 0;) {
X
X		/* read however many chars are waiting */
X		timedout = 0;
X		alarm(seconds);
X		numread = read(0, inbuf, left);
X		alarm(0);
X		if (timedout)
X			return(TIMEOUT);
X		left -= numread;
X
X		if (DEBUG)
X			fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread);
X
X		/* now process part of packet we just read */
X
X		for (j =  0; j < numread; j++) 
X			{  
X				buff[bfctr] = c = inbuf[j] & 0xff;
X				fileread++;
X
X				if (CRCMODE)  /* CRC */
X					chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
X
X				else        /* checksum */
X		       			chksm = ((chksm+c) & 0xff);
X
X				if (CHECKLENGTH && fileread > filelength)	/* past EOF ? */
X					continue;
X
X				if (tmode) 		/* text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == CR || c == 0)	/* skip CRs and nulls */
X						continue;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			else if (!recfin)	/* don't increment if past EOF */
X						bfctr++;
X					}
X				else if (amode) 	/* Apple macintosh text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == 0)		/* skip nulls */
X						continue;
X					else if (c == CR)	/* translate CR to LF */
X						buff[bfctr] = LF;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			if (!recfin)	/* don't increment if past EOF */
X						bfctr++;
X					}
X				else			/* binary */
X					bfctr++;
X
X		     	}	
X
X		/* go to sleep to save uneeded system calls while kernel
X		   is reading data from serial line, fudge constant from 10 to
X		   9 to avoid sleeping too long
X		*/
X		if (left && !TOOBUSY)
X			sleep ((left<SLEEPNUM ? left:SLEEPNUM) * 9/ttyspeed);
X	}
X
X	if (CHECKLENGTH && fileread >= filelength)
X		logitarg("File end from YMODEM length found in sector %s\n",
X		  sectdisp(recvsectcnt,bufsize,1));
X	*checksum = chksm;
X	*bufctr = bfctr;
X	return(0);
X}
X
X/* send a byte to data stream */
X
Xsendbyte(data)
Xchar data;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: sendbyte %02xh\n", data & 0xff);
X
X	if (write(1, &data, 1) != 1)  	/* write the byte (assume it goes NOW; no flushing needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/* send a buffer to data stream */
X
Xwritebuf(buffer, nbytes)
Xchar *buffer;
Xint  nbytes;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: writebuf (%d bytes)\n", nbytes);
X
X	if (write(1, buffer, nbytes) != nbytes)		/* write the buffer (assume no TIOCFLUSH needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/* set and restore tty modes for XMODEM transfers */
X
Xstruct termio ttys;
Xstruct stat statbuf;		/* for terminal message on/off control */
X
Xint wason;			/* holds status of tty read write/modes */
Xchar *tty;			/* current tty name */
X
X
Xsetmodes()
X	{
X	char *ttyname();
X	struct termio ttysnew;
X
X	extern onintr();
X
X	sleep(2);			/* let the output appear */
X	if (ioctl(0,TCGETA,&ttys)<0)  /* get tty params */
X		error("Can't get TTY Parameters", TRUE);
X
X	tty = ttyname(0);  /* identify current tty */
X	
X	if (ioctl(0,TCGETA,&ttysnew)<0)  /* get tty params */
X		error("Can't get TTY Parameters", TRUE);
X	ttysnew.c_cc[4] = 1;		/* VMIN */
X	ttysnew.c_cc[5] = 0;		/* VTIME */
X	ttysnew.c_iflag = 0;
X	ttysnew.c_oflag = 0;
X	ttysnew.c_lflag = 0;
X	ttysnew.c_cflag &= ~CSIZE;
X	ttysnew.c_cflag |= CS8;
X	ttysnew.c_cflag &= ~PARENB;
X	if (ioctl(0,TCSETA,&ttysnew)<0)  /* set new paramters */
X		error("Can't set new TTY Parameters", TRUE);
X
X	if (stat(tty, &statbuf) < 0)  /* get tty status */ 
X		error("Can't get your TTY Status", TRUE);
X
X	if (statbuf.st_mode & 022)	/* Need to turn messages off */
X		if (chmod(tty, (int)statbuf.st_mode & ~022) < 0)
X			error("Can't change  TTY mode", TRUE);
X		else 
X			wason = TRUE;
X	else 
X		wason = FALSE;
X
X	/* set up signal catcher to restore tty state if we are KILLed */
X
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, onintr);
X	}
X
X/* restore normal tty modes */
X
Xrestoremodes(errcall)
Xint errcall;
X	{
X	if (wason)
X		if (chmod(tty, (int)statbuf.st_mode | 022) < 0)
X			error("Can't change TTY mode", FALSE);
X	if (ioctl(0,TCSETA,&ttys) < 0)
X		{ if (!errcall)
X		   error("RESET - Can't restore normal TTY Params", FALSE);
X		else
X		     printf("RESET - Can't restore normal TTY Params\n");
X		}
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, SIG_DFL);
X	return;
X	}
X
X
X
X
X/* signal catcher */
Xonintr()
X	{
X	error("Kill signal; bailing out", TRUE);
X	}
X
X/* create string with a timestamp for log file */
X
Xchar *stamptime()
X{
X	char *asctime();		/* stuff to get timestamp */
X	struct tm *localtime(), *tp;
X	long now;
X
X	time(&now);
X	tp = localtime(&now);
X	return(asctime(tp));
X}
X
X
X
X/* get tty speed for time estimates */
X
Xgetspeed()
X	{
X	static int speedtbl[] = {0, 50, 75, 110, 134, 150, 200, 300, 600,
X	1200, 1800, 2400, 4800, 9600, 19200, 0};
X	struct termio ttystemp;
X
X	if (ioctl(0,TCGETA,&ttystemp) < 0)	/* get tty structure */
X		error("Can't get TTY parameters", FALSE);
X	if ((ttystemp.c_cflag & 017) >= 0 && (ttystemp.c_cflag & 017) <= 14)
X		{
X		ttyspeed = speedtbl[ttystemp.c_cflag & 017];
X		logitarg ("Line speed = %d bits per second\n", ttyspeed);
X		}
X	else
X		{
X		ttyspeed = 1200;
X		logit ("Can't determine line speed; assuming 1200 bps\n");
X		}
X	}
SHAR_EOF
chmod 0644 getput.sysv.c || echo "restore of getput.sysv.c fails"
echo "x - extracting misc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > misc.c &&
X#include "xmodem.h"
X
X/*  Print Help Message  */
Xhelp()
X	{
X	fprintf(stderr, "\nUsage:  \n\txmodem ");
X	fprintf(stderr, "-[rb!rt!ra!sb!st!sa][options] filename\n");
X	fprintf(stderr, "\nMajor Commands --");
X	fprintf(stderr, "\n\trb <-- Receive Binary");
X	fprintf(stderr, "\n\trt <-- Receive Text");
X	fprintf(stderr, "\n\tra <-- Receive Apple macintosh text");
X	fprintf(stderr, "\n\tsb <-- Send Binary");
X	fprintf(stderr, "\n\tst <-- Send Text");
X	fprintf(stderr, "\n\tsa <-- Send Apple macintosh text");
X	fprintf(stderr, "\nOptions --");
X	fprintf(stderr, "\n\ty  <-- Use YMODEM Batch Mode on transmit");
X	fprintf(stderr, "\n\tm  <-- Use MODEM7 Batch Mode on transmit");
X	fprintf(stderr, "\n\tk  <-- Use 1K packets on transmit");
X	fprintf(stderr, "\n\tc  <-- Select CRC mode on receive");
X	fprintf(stderr, "\n\tt  <-- Indicate a TOO BUSY Unix system");
X	fprintf(stderr, "\n\td  <-- Delete xmodem.log file before starting");
X	fprintf(stderr, "\n\tl  <-- (ell) Turn OFF Log File Entries");
X	fprintf(stderr, "\n\tx  <-- Include copious debugging information in log file");
X	fprintf(stderr, "\n");
X	}
X
X/* get type of transmission requested (text or binary) */
Xgettype(ichar)
Xchar ichar;
X	{
X	if (ichar == 't' || ichar == 'T')
X		return('t');
X	else if (ichar == 'b' || ichar == 'B')
X		return('b');
X	else if (ichar == 'a' || ichar == 'A')
X		return('a');
X	else
X		error("Invalid Send/Receive Parameter - not t or b", FALSE);
X	return('\0');
X	}
X
X/* return a string containing transmission type */
Xchar *
Xprtype(ichar)
Xchar ichar;
X	{
X	if (ichar == 't' || ichar == 'T')
X		return("text");
X	else if (ichar == 'b' || ichar == 'B')
X		return("binary");
X	else if (ichar == 'a' || ichar == 'A')
X		return("apple");
X	else
X		return("");
X	}
X
X/* print error message and exit; if mode == TRUE, restore normal tty modes */
Xerror(msg, mode)
Xchar *msg;
Xint mode;
X	{
X	if (mode)
X		restoremodes(TRUE);  /* put back normal tty modes */
X	fprintf(stderr, "\r\n%s\n", msg);
X	if ((LOGFLAG || DEBUG) && (LOGFP != NULL))
X		{   
X		fprintf(LOGFP, "XMODEM Fatal Error:  %s\n", msg);
X	    	fclose(LOGFP);
X		}
X	exit(-1);
X	}
X
X
X/* Construct a proper (i.e. pretty) sector count for messages */
X
Xchar
X*sectdisp(recvsectcnt, bufsize, plus1)
Xlong recvsectcnt;
Xint bufsize, plus1;
X	{
X	static char string[20];
X	if (plus1)
X		recvsectcnt += (bufsize == 128) ? 1 : 8;
X	if (bufsize == 128 || recvsectcnt == 0)
X		sprintf (string, "%d", recvsectcnt);
X	else
X		sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
X	return(string);
X	}
X
X/* type out debugging info */
Xxmdebug(str)
Xchar *str;
X	{
X	if (DEBUG && (LOGFP != NULL))
X		fprintf(LOGFP,"DEBUG: '%s'\n",str);
X	}
X
X/* print elapsed time and rate of transfer in logfile */
X
Xint quant[] = { 60, 60, 24};	
Xchar sep[3][10] = { "second", "minute", "hour" };
X
Xprtime (numsect, seconds)
Xlong numsect;
Xtime_t seconds;
X
X{
X	register int i;
X	register int Seconds;
X	int nums[3];
X	int rate;
X
X	if (!LOGFLAG || numsect == 0)
X		return(0);
X
X	Seconds = (int)seconds;
X	Seconds = (Seconds > 0) ? Seconds : 0;
X
X	rate = (Seconds != 0) ? 128 * numsect/Seconds : 0;
X
X	for (i=0; i<3; i++) {
X		nums[i] = (Seconds % quant[i]);
X		Seconds /= quant[i];
X	}
X
X	fprintf (LOGFP, "%ld Sectors Transfered in ", numsect);
X
X	if (rate == 0)
X		fprintf (LOGFP, "0 seconds");
X	else
X		while (--i >= 0)
X			if (nums[i])
X				fprintf (LOGFP, "%d %s%c ", nums[i], &sep[i][0],
X					nums[i] == 1 ? ' ' : 's');
X	fprintf (LOGFP, "\n");
X
X	if (rate != 0)
X		fprintf (LOGFP, "Transfer Rate = %d Characters per Second\n", rate);
X
X	return(0);
X}
X
X/* Print elapsed time estimate */
X
Xprojtime (numsect, fd)
Xlong numsect;
XFILE *fd;
X	{
X	register int i;
X	register int seconds;
X	int nums[3];
X
X	if (numsect == 0)
X		return (0);
X
X/* constant below should really be 1280; reduced to 90% to account for time lost in overhead */
X
X	seconds = 1422 * numsect / ttyspeed + 1;
X
X	for (i=0; i<3; i++) {
X		nums[i] = (seconds % quant[i]);
X		seconds /= quant[i];
X	}
X
X	fprintf (fd, "Estimated transmission time ");
X
X	while (--i >= 0)
X		if (nums[i])
X			fprintf (fd, "%d %s%c ", nums[i], &sep[i][0],
X				nums[i] == 1 ? ' ' : 's');
X	fprintf (fd, "\n");
X	return (0);
X	}
SHAR_EOF
chmod 0644 misc.c || echo "restore of misc.c fails"
echo "x - extracting receive.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > receive.c &&
X#include "xmodem.h"
X
X/**  receive a file  **/
X
X/* returns TRUE if in the midst of a batch transfer */
X/* returns FALSE if no more files are coming */
X
X/* This routine is one HUGE do-while loop with far to many indented levels.
X * I chose this route to facilitate error processing and to avoid GOTOs.
X * Given the troubles I've had keeping the nested IF statements straight,
X * I was probably mistaken...
X */
X
Xrfile(name)
Xchar *name;
X{
X
Xchar *sectdisp();
Xchar *cpm_unix();
Xchar *strcpy();
Xchar *ctime();
Xtime_t time();
X
Xint fd,     /* file descriptor for created file */
Xchecksum,   /* packet checksum */
Xfirstchar,  /* first character of a packet */
Xsectnum,    /* number of last received packet (modulo 128) */
Xsectcurr,   /* second byte of packet--should be packet number (mod 128) */
Xsectcomp,   /* third byte of packet--should be complement of sectcurr */
Xtmode,      /* text mode if true */
Xamode,      /* apple mode if true */
Xerrors,     /* count of errors for each packet */
Xsterrors,   /* count of errors during startup handshake */
Xerrorflag,  /* set true when packet (or first char of putative packet) is invalid */
Xfatalerror, /* set within main "read-packet" Do-While when bad error found */
Xinchecksum, /* incoming checksum or CRC */
Xexpsect,    /* expected number of sectors (YMODEM batch) */
Xfirstwait,  /* seconds to wait for first character in a packet */
Xbufsize;    /* packet size (128 or 1024) */
Xlong recvsectcnt;   /* running sector count (128 byte sectors) */
Xlong modtime;       /* Unix style file mod time from YMODEM header */
Xint filemode;       /* Unix style file mode from YMODEM header */
Xlong readbackup;    /* "backup" value for characters read in file */
Xtime_t timep[2];    /* used in setting mod time of received file */
Xchar *p;    /* generic pointer */
Xint bufctr; /* number of real chars in read packet */
Xunsigned char *nameptr; /* ptr in filename for MODEM7 protocol */
Xtime_t start;       /* starting time of transfer */
Xint openflag = FALSE;   /* is file open for writing? */
X
Xlogit("----\nXMODEM File Receive Function\n");
Xif (CRCMODE)
Xlogit("CRC mode requested\n");
X
XBATCH = FALSE;          /* don't know if really are in batch mode ! */
Xfatalerror = FALSE;
Xfirstwait = WAITFIRST;  /* For first packet, wait short time */
Xsectnum = errors = recvsectcnt = 0;
Xbufsize = 128;
Xmodtime = 0l; filemode = 0;
Xfilelength = 0l; fileread =0l; CHECKLENGTH = FALSE;
X
Xtmode = (XMITTYPE == 't') ? TRUE : FALSE;
Xamode = (XMITTYPE == 'a') ? TRUE : FALSE;
X
X/* start up transfer */
X
Xsterrors = 0;
Xflushin();         /* flush input queue */
X
Xif (CRCMODE)        
X{
X	sendbyte(CRCCHR);
X	if (LONGPACK && !MDM7BAT)
X		sendbyte(KCHR);
X}
Xelse
X	sendbyte(NAK);
X
X
Xdo                  /* start of MAIN Do-While loop to read packets */
X{   
X	errorflag = FALSE;
X	do              /* start by reading first byte in packet */
X	{
X		firstchar = readbyte(firstwait);
X	} 
X	while ((firstchar != SOH) 
X	    && (firstchar != STX) 
X	    && (firstchar != EOT) 
X	    && (firstchar != ACK || recvsectcnt > 0) 
X	    && (firstchar != TIMEOUT) 
X	    && (firstchar != CAN || recvsectcnt > 0));
X
X	if (firstchar == EOT)           /* check for REAL EOT */
X	{
X		flushin();
X		sendbyte(NAK);              /* NAK the EOT */
X		if ((firstchar = readbyte(3)) != EOT)   /* check next character */
X		{
X			logit("Spurious EOT detected; ignored\n");
X			if ((firstchar == SOH) || (firstchar == STX) ||
X			    (firstchar == ACK && recvsectcnt == 0) ||
X			    (firstchar == CAN && recvsectcnt == 0) ||
X			    (firstchar == TIMEOUT))
X				break;
X			else
X			{
X				firstchar = 0;
X				errorflag = TRUE;
X			}
X		}
X	}
X
X	if (firstchar == TIMEOUT)       /* timeout? */
X	{  
X		if (recvsectcnt > 0)
X			logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
X		errorflag = TRUE;
X	}
X
X	if (firstchar == CAN)           /* bailing out? (only at beginning) */
X	{
X		if ((readbyte(3) & 0x7f) == CAN)
X			error("Reception canceled at user's request",TRUE);
X		else
X		{
X			errorflag = TRUE;
X			logit("Received single CAN character\n");
X		}
X	}
X
X	if (firstchar == ACK)           /* MODEM7 batch? (only at beginning) */
X	{
X		int i,c; 
X
X		logit("MODEM7 Batch Protocol\n");
X		nameptr = buff;
X		checksum = 0;
X
X		for (i=0; i<NAMSIZ; i++)
X		{
X			c = readbyte(3);
X
X			if (c == CAN)
X			{
X				if (readbyte(3) == CAN)
X					error("Program Canceled by User", TRUE);
X				else
X				{
X					logit("Received single CAN character in MODEM7 filename\n");
X					errorflag = TRUE;
X					break;
X				}
X			}
X
X			if (c == EOT && i == 0)
X			{
X				sendbyte(ACK);          /* acknowledge EOT */
X				logit("MODEM7 Batch Receive Complete\n");
X				return (FALSE);
X			}
X
X			if (c == TIMEOUT)
X			{
X				logit("Timeout waiting for MODEM7 filename character\n");
X				errorflag = TRUE;
X				break;
X			}
X
X			if (c == BAD_NAME)
X			{
X				logit("Error during MODEM7 filename transfer\n");
X				errorflag = TRUE;
X				break;
X			}
X
X			*nameptr++ = c;
X			checksum += c;
X			sendbyte(ACK);
X		}
X
X		if (!errorflag)
X		{
X			c = readbyte(3);
X			if (c == CTRLZ)     /* OK; end of string found */
X			{
X				sendbyte(checksum + CTRLZ);
X				if (readbyte(15) == ACK)     /* file name found! */
X				{
X					xmdebug("MODEM7 file name OK");
X					*nameptr = '\000';  /* unixify the file name */
X					name = cpm_unix(buff);
X					BATCH = TRUE;
X					logitarg("MODEM7 file name: %s\n", name);
X					errors = 0;     /* restart crc handshake */
X					sleep(2);       /* give other side a chance */
X				}
X				else
X				{
X					logit("Checksum error in MODEM7 filename\n");
X					errorflag = TRUE;
X				}
X			}
X			else
X			{
X				logit("Length error in MODEM7 filename\n");
X				errorflag = TRUE;
X			}
X		}
X	}
X
X
X	if (firstchar == SOH || firstchar == STX)  /* start reading packet */
X	{
X		bufsize = (firstchar == SOH) ? 128 : 1024;
X
X		if (recvsectcnt == 0)           /* 1st data packet, initialize */
X		{
X			if (bufsize == 1024)
X				logit("1K packet mode chosen\n");
X			start = time((time_t *) 0);
X			errors = 0;
X			firstwait = 5;
X		}
X
X		sectcurr = readbyte(3);
X		sectcomp = readbyte(3);
X		if ((sectcurr + sectcomp) == 0xff)  /* is packet number checksum correct? */
X		{  
X			if (sectcurr == ((sectnum+1) & 0xff))   /* is packet number correct? */
X			{  
X				if (DEBUG)
X					fprintf(LOGFP,"DEBUG: packet %d started\n", sectnum);
X
X				/* Read, process and calculate checksum for a buffer of data */
X
X				readbackup = fileread;
X				if (readbuf(bufsize, 1, tmode, amode, recvsectcnt, &checksum, &bufctr) != TIMEOUT) 
X				{
X
X					/* verify checksum or CRC */
X
X					if (CRCMODE) 
X					{
X						checksum &= 0xffff;
X						inchecksum = readbyte(3);  /* get 16-bit CRC */
X						inchecksum = (inchecksum<<8) | readbyte(3);
X					}
X
X					else
X						inchecksum = readbyte(3);  /* get simple 8-bit checksum */
X
X					if (inchecksum == checksum) /* good checksum, hence good packet */
X					{  
X						xmdebug("checksum ok");
X						errors = 0;
X						recvsectcnt += (bufsize == 128) ? 1 : 8;
X						sectnum = sectcurr; 
X
X						if (!openflag)      /* open output file if necessary */
X						{
X							openflag = TRUE;
X							if ((fd = creat(name, CREATMODE)) < 0)
X							{
X								sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X								error("Can't create file for receive", TRUE);
X							}
X							if (!BATCH)
X								logitarg("File Name: %s\n", name);
X						}
X
X						if (write(fd, (char *) buff, bufctr) != bufctr)
X						{
X							close(fd);
X							unlink(name);
X							error("File Write Error", TRUE);
X						}
X						else
X						{
X							flushin();          /* flush input */
X							sendbyte(ACK);      /* ACK the received packet */
X						}
X					}
X
X					/* Start handling various errors and special conditions */
X
X					else        /* bad checksum */
X					{  
X						logitarg("Checksum Error on Sector %s:  ", sectdisp(recvsectcnt,bufsize,1));
X						logitarg("sent=%x  ", inchecksum);
X						logitarg("recvd=%x\n", checksum);
X						fileread = readbackup;
X						errorflag = TRUE;
X					}
X				}
X
X				else    /* read timeout */
X				{
X					logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
X					fileread = readbackup;
X					errorflag = TRUE;
X				}
X			}
X
X			else        /* sector number is wrong OR Ymodem filename */
X			{ 
X				if (sectcurr == 0 && recvsectcnt == 0)  /* Ymodem file-name packet */
X				{
X					logit("YMODEM Batch Protocol\n");
X
X					/* Read and process a file-name packet */
X
X					if (readbuf(bufsize, 1, FALSE, FALSE, recvsectcnt, &checksum, &bufctr) != TIMEOUT) 
X					{
X
X						/* verify checksum or CRC */
X
X						if (CRCMODE) 
X						{
X							checksum &= 0xffff;
X							inchecksum = readbyte(3);  /* get 16-bit CRC */
X							inchecksum = (inchecksum<<8) | readbyte(3);
X						}
X
X						else
X							inchecksum = readbyte(3);  /* get simple 8-bit checksum */
X
X						if (inchecksum == checksum) /* good checksum, hence good filename */
X						{
X							xmdebug("checksum ok");
X							strcpy(name, (char *)buff);
X							expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]);
X							BATCH = TRUE;
X							YMDMBAT = TRUE;
X							if (strlen(name) == 0)  /* check for no more files */
X							{
X								flushin();          /* flush input */
X								sendbyte(ACK);      /* ACK the packet */
X								logit("YMODEM Batch Receive Complete\n");
X								return (FALSE);
X							}
X							unixify(name);       /* make filename canonical */
X
X							/* read rest of YMODEM header */
X							p = (char *)buff + strlen((char *)buff) + 1;
X							sscanf(p, "%ld%lo%o", &filelength, &modtime, &filemode);
X							logitarg("YMODEM file name: %s\n", name);
X							fileread = 0l;
X							if (filelength)
X							{
X								CHECKLENGTH = TRUE;
X								logitarg("YMODEM file size: %ld\n", filelength);
X							}
X							else if (expsect)
X								logitarg("YMODEM estimated file length %d sectors\n", expsect);
X							if (modtime)
X							{
X								logitarg("YMODEM file date: %s", ctime(&modtime));
X							}
X							if (filemode)
X								logitarg("YMODEM file mode: %o", filemode);
X
X							sendbyte(ACK);      /* ACK the packet */
X							firstwait = WAITFIRST;  /* reset to negotiate */
X						}
X
X						else                /* bad filename checksum */
X						{
X							logit("checksum error on filename sector\n");
X							errorflag = TRUE;
X						}
X					}
X					else
X					{
X						logit("Timeout while reading filename packet\n");
X						errorflag = TRUE;
X					}
X				}
X
X				else if (sectcurr == sectnum)   /* duplicate sector? */
X				{  
X					logitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
X					flushin();                  /* REALLY flush input */
X					while(readbyte(1) != TIMEOUT)
X						;
X					sendbyte(ACK);
X				}
X				else                /* no, real phase error */
X				{
X					logitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
X					errorflag = TRUE;
X					fatalerror = TRUE;
X				}
X			}
X		}
X
X		else        /* bad packet number checksum */
X		{  
X			logitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
X			errorflag = TRUE;
X		}
X
X	}           /* END reading packet loop */
X
X	if (errorflag && !fatalerror && recvsectcnt != 0)   /* Handle errors */
X	{  
X		errors++;
X
X		if (errors >= ERRORMAX)     /* over error limit? */
X			fatalerror = TRUE;
X		else                        /* flush input and NAK the packet */
X		{
X			flushin();
X			while (readbyte(1) != TIMEOUT)  /* wait for line to settle */
X				;
X			sendbyte(NAK);
X		}
X	}
X
X	if (recvsectcnt == 0 && errorflag && firstchar != EOT) 	/* handle startup handshake */
X	{
X		sterrors++;
X
X		if (sterrors >= STERRORMAX)
X			fatalerror = TRUE;
X
X		else if (CRCMODE && sterrors == CRCSWMAX && !YMDMBAT)
X		{
X			CRCMODE = FALSE;
X			logit("Sender not accepting CRC request, changing to checksum\n");
X			sendbyte(NAK);
X		}
X
X		else if (!CRCMODE && sterrors == CRCSWMAX && !YMDMBAT)
X		{
X			CRCMODE = TRUE;
X			logit("Sender not accepting checksum request, changing to CRC\n");
X			sendbyte(CRCCHR);
X			if (LONGPACK && !MDM7BAT)
X				sendbyte(KCHR);
X		}
X
X		else if (CRCMODE)
X			{
X			sendbyte(CRCCHR);
X			if (LONGPACK && !MDM7BAT)
X				sendbyte(KCHR);
X			}
X
X		else
X			sendbyte(NAK);
X	}
X}
Xwhile ((firstchar != EOT) && !fatalerror);   /* end of MAIN Do-While */
X
Xif ((firstchar == EOT) && !fatalerror)  /* normal exit? */
X{
X	if (openflag)       /* close the file */
X		close(fd);
X	sendbyte(ACK);      /* ACK the EOT */
X	logit("Receive Complete\n");
X	prtime (recvsectcnt, time((time_t *) 0) - start);
X
X	if (openflag && modtime)   /* set file modification time */
X	{
X		timep[0] = time((time_t *) 0);
X		timep[1] = modtime;
X		utime(name, timep);
X	}
X
X	if (BATCH)          /* send appropriate return code */
X		return(TRUE);
X	else
X		return(FALSE);
X}
Xelse                /* no, error exit */
X{ 
X	if (openflag)
X	{
X		sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X		close(fd);
X		unlink(name);
X		error("ABORTED -- Too Many Errors--deleting file", TRUE);
X	}
X	else if (recvsectcnt != 0)
X		error("ABORTED -- Too Many Errors", TRUE);
X	else
X		error("ABORTED -- Remote system is not responding", TRUE);
X}
Xreturn(FALSE);
X
X}
SHAR_EOF
chmod 0644 receive.c || echo "restore of receive.c fails"
echo "x - extracting send.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > send.c &&
X/**  send a file  **/
X
X/*
X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
X *
X * If "name" is NULL; close out the BATCH send.
X */
X
X#include "xmodem.h"
X
Xsfile(name)
Xchar *name;
X	{
X
X	char *sectdisp();
X	time_t time();
X	char *strcpy();
X	char *unix_cpm();
X	char *cpmify();
X	long countnl();
X
X	extern unsigned short crctab[1<<B];	/* CRC-16 constant values, see getput.c */
X
X	register int bufctr, 		/* array index for data buffer */
X	sectnum;			/* packet number for packet header */
X
X	register unsigned short checksum; 	/* checksum/crc */
X
X	char blockbuf[BBUFSIZ+6];	/* holds packet as it is constructed */
X
X	struct stat filestatbuf;	/* file status info */
X
X	int fd, 		/* file descriptor for file being transmitted */
X	attempts,		/* number of attempts made to transmit a packet */
X	nlflag, 		/* flag that we have to send a LF in next packet */
X	sendfin, 		/* flag that we are sending the last packet */
X	closeout,		/* flag that we are closing out batch send */
X	startup,		/* flag that we are starting batch send */
X	tmode,			/* TRUE for text mode */
X	amode,			/* TRUE for apple mode */
X	filepack,		/* TRUE when sending first packet */
X	buf1024,		/* TRUE when sending 1K packets */
X	bbufcnt,		/* array index for packet */
X	firstchar,		/* first character in protocol transaction */
X	bufsize,		/* packet size (128 or 1024) */
X	sendresp;  		/* response char to sent block received from remote*/
X	long sentsect;		/* count of 128 byte sectors actually sent */
X	long expsect;		/* count of 128 byte sectors expected to be sent */
X	time_t start;		/* starting time of transfer */
X	char c;
X
X	nbchr = 0;  /* clear buffered read char count */
X
X	CRCMODE = FALSE;	/* Receiver determines use of crc or checksum */
X
X	buf1024 = LONGPACK;	/* set packet size flag to command line switch */
X
X	closeout = FALSE; startup = TRUE; filepack = FALSE;	/* indicate state of batch transfer */
X
X	tmode = (XMITTYPE == 't') ? TRUE : FALSE;	/* set text mode */
X	amode = (XMITTYPE == 'a') ? TRUE : FALSE;	/* set apple mode */
X
X	/* Check on NULL file name */
X	if (strcmp(name,"") == 0)
X		{
X		if (BATCH)
X			closeout = TRUE;
X		else
X			{
X			sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X			error("NULL file name in send", TRUE);
X			}
X		}
X
X	if (!closeout)		/* Are we closing down batch? */
X		{			/* no; let's send a file */
X		logit("----\nXMODEM Send Function\n");
X
X		if ((fd = open(name, 0)) < 0)	
X			{  
X			sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X     	   		error("Can't open file for send", TRUE);
X			}
X	
X		stat(name, &filestatbuf);  /* get file status bytes */
X		if (tmode)		   /* count up NLs */
X			filestatbuf.st_size += countnl(fd);
X		expsect = (filestatbuf.st_size/128) + 1;
X	
X		if (LOGFLAG)
X			{   
X		    	fprintf(LOGFP, "File Name: %s\n", name);
SHAR_EOF
echo "End of part 1"
echo "File send.c is continued in part 2"
echo "2" > s2_seq_.tmp
exit 0
-- 
Keith Petersen
Arpa: W8SDZ@SIMTEL20.ARPA
Uucp: {bellcore,decwrl,harvard,lll-crg,ucbvax,uw-beaver}!simtel20.arpa!w8sdz
GEnie: W8SDZ

w8sdz@brl-smoke.arpa (Keith B. Petersen ) (06/02/88)

This is version 3.6 (finished 4/88) of Steve Grandi's 4.2/4.3 BSD Unix
xmodem program which includes a few bugfixes and some enhancements
(requested by Macintosh users) stimulated by the xmodem release through
comp.sources.unix.  See the file update.doc for details.

---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.20)
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  README
#	  batch.c
#	  getput.c
#	  getput.sysv.c
#	  misc.c
#	  receive.c
#	  send.c
#	  tip.diffs
#	  update.doc
#	  xmodem.1
#	  xmodem.c
#	  xmodem.h
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
XOBJECTS = xmodem.o getput.o misc.o send.o receive.o batch.o
XCFLAGS = -O
X
Xxmodem: $(OBJECTS)
X	cc $(CFLAGS) $(OBJECTS) -o xmodem
X
X$(OBJECTS): xmodem.h
X
Xprint: 
X	lpr -p -Pvmslp xmodem.h xmodem.c getput.c receive.c send.c batch.c \
X	misc.c Makefile update.doc README xmodem.1 getput.sysv.c
X
Xlint:
X	lint xmodem.c getput.c receive.c send.c batch.c misc.c | imprint
X
Xshar:
X	shar README update.doc Makefile xmodem.1 xmodem.h > xmodem.shar.1
X	shar xmodem.c receive.c misc.c > xmodem.shar.2
X	shar getput.c getput.sysv.c > xmodem.shar.3
X	shar batch.c send.c > xmodem.shar.4
X	shar tip.diffs > xmodem.shar.5
X
Xbigshar: 
X	shar README update.doc Makefile xmodem.1 xmodem.h xmodem.c getput.c \
X	getput.sysv.c receive.c misc.c batch.c send.c tip.diffs > xmodem.shar
X
Xtarz: 
X	tar cvf xmodem.tar README update.doc Makefile xmodem.1 xmodem.h \
X	xmodem.c getput.c getput.sysv.c receive.c misc.c batch.c send.c \
X	tip.diffs ymodem.doc
X	compress xmodem.tar
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XThis is version 3.6 (finished 4/88) of the xmodem program which includes a
Xfew bugfixes and some enhancements (requested by Macintosh users)
Xstimulated by the xmodem release through comp.sources.unix.  See the file
Xupdate.doc for details. 
X
X--------------------------------------------------------------------------------
X
XThis is version 3.4 (finished 10/87) of the xmodem program, a full-featured
XXMODEM implementation for 4.3BSD.  Since the previous release (version
X3.2, see volume 7 of the archives), substantial improvements have been
Xmade. See the file update.doc for details.  Also, some attempt has been
Xmade to support SysV Unix systems; see below.
X
XAs far as I am concerned, this program has reached the end of its evolution.
XNewer protocols (such as ZMODEM) will not be incorporated into xmodem.  Check
Xout Chuck Forsberg's rz/sz programs if you are interested in ZMODEM.
X
XTo answer one oft-asked question: No, I don't know how to tie this
Xfull-featured xmodem program into tip or cu for file transfers when calling
Xout from a 4.3BSD system.  4.3BSD tip does have some undocumented hooks
Xfor tying into other programs through redirecting file descriptors, but my
Xminimal attempts to utilize these hooks have failed.  However, several
Xyears back, I built a VERY early version of xmodem (lacking XMODEM/CRC,
XXMODEM-1K, MODEM7 batch or YMODEM) directly into 4.2BSD tip.  The changes
Xworked unmodified in 4.3BSD; the diff files are contained in the file
Xtip.diffs.
X
X--------------------------------------------------------------------------------
X
XThe xmodem program implements the Christensen (XMODEM) file transfer
Xprotocol for moving files between 4.2/4.3BSD Unix systems and microcomputers.
XThe XMODEM/CRC protocol, the MODEM7 batch protocol, the XMODEM-1K
Xblock protocol and the YMODEM batch protocol are all supported by xmodem.
XFor details of the protocols, see the document edited by Chuck Forsberg titled
XXMODEM/YMODEM Protocol Reference (the latest version is dated 8-4-87).
X
XThis program runs on 4.2/4.3BSD systems ONLY.  It has been tested on VAXes
Xand Suns against the MEX-PC program from Niteowl Software and the ZCOMM and
XDSZ programs from Omen Technology.
X
XI have tried to keep the 4.2isms (select system call, 4.2BSD/v7 tty structures,
Xgettimeofday system call, etc.) confined to the source file getput.c; but I 
Xmake no guarantees.  Also, I have made no attempt to keep variable names 
Xunder 7 characters.  A version of getput.c that MAY work on Sys V Unix
Xsystems is included.
X
X--------------------------------------------------------------------------------
X
XThanks to Emmet Gray (ihnp4!uiucuxc!fthood!egray) and John Rupley 
X(arizona!rupley!root) for the following notes about converting xmodem to Sys V.
XSince I don't have a Sys V system to test a Sys V version, I won't even try.
X
X1) Change the includes in xmodem.h from <sys/time.h> to <time.h>
X   and from <sgtty.h> to <termio.h>
X
X2) Convert the occurrences of rindex to strrchr in batch.c
X
X3) Substitute getput.sysv.c for getput.c
X
X--------------------------------------------------------------------------------
X
XProgram history:
X
XDescended from UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
X
XBased on XMODEM Version 1.0 by Brian Kantor, UCSD (3/84)  (Don't blame him 
Xfor what follows....)
X
XVersion 2.0 (CRC-16 and Modem7 batch file transfer) (5/85)
X
XVersion 2.1 (1K packets) (7/85)
X
XVersion 2.2 (general clean-ups and multi-character read speed-ups) (9/85)
X
XVersion 2.3 (nap while reading packets; split into several source files) (1/86)
X
XVersion 3.0 (Ymodem batch receive; associated changes) (2/86)
X
XVersion 3.1 (Ymodem batch send; associated changes) (8/86)
X
XVersion 3.2 (general cleanups) (9/86) 
X    (Released to the world 1/87)
X
XVersion 3.3 (general fixes and cleanups; see update.doc) (5/87)
X
XVersion 3.4 (general fixes and cleanups; see update.doc) (10/87) 
X    (Released to the world 3/88)
X
XVersion 3.5 (general fixes and cleanups; see update.doc) (3/88)
X
XVersion 3.6 (general fixes and cleanups; text file translation for Mac; 
X    see update.doc) (4/88) 
X    (Released to the world 4/88)
X
X--------------------------------------------------------------------------------
X
XPlease send bug fixes, additions and comments to:
XSteve Grandi, National Optical Astronomy Observatories (Tucson, Arizona)
X	{ihnp4,ncar,arizona,...}!noao!grandi  grandi@noao.arizona.edu
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
echo "x - extracting batch.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > batch.c &&
X/*
X *  Various routines for batch transfer
X */
X
X#include "xmodem.h"
X
X/* make sure filename sent or received in YMODEM batch is canonical. */
X
X/* Incoming: Turn Unix '/' into CP/M ':' and translate to all lower case.
X * Remove trailing dot.
X */
X
Xunixify (name)
Xchar *name;
X	{
X	char *ptr;
X
X	/* change '/' to ':' and convert to lower case */
X	for (ptr=name; *ptr; ++ptr)
X		{
X		if (*ptr == '/')
X			*ptr = ':';
X		if (isupper (*ptr))
X			*ptr |= 040;
X		}
X
X	/* remove trailing dot if present */
X	ptr--;
X	if (*ptr == '.')
X		*ptr = '\0';
X	}
X
X/* make sure filename sent or received in YMODEM batch is canonical. */
X
X/* Outgoing: Turn ':' into '/' (for symmetry!) and turn into all lower case.
X * Remove everything before last '/'.  Use "filename" to hold final name.
X */
X
Xchar *
Xcpmify (name)
Xchar *name;
X	{
X	char *ptr, *slash;
X	char *strcpy();
X
X	/* find last '/' and copy rest of name */
X
X	slash = name;
X	for (ptr=name; *ptr; ++ptr)
X		if (*ptr == '/')
X			slash = ptr + 1;
X	strcpy (filename, slash);
X
X	/* change ':' to '/' and covert to all lower case */
X
X	for (ptr=filename; *ptr; ++ptr)
X		{
X		if (*ptr == ':')
X			*ptr = '/';
X		if (isupper (*ptr))
X			*ptr |= 040;
X		}
X	return (filename);
X	}
X
X
X/* convert a CP/M file name received in a MODEM7 batch transfer
X * into a unix file name mapping '/' into ':', converting to all
X * upper case and adding dot in proper place.  
X * Use "filename" to hold name.
X * Code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xchar *
Xcpm_unix (string)
Xunsigned char *string;
X{
X	register int i;
X	unsigned char *iptr, temp;
X	register char *optr;
X
X	if (*string == '\0')
X		error("Null file name in MODEM7 batch receive", TRUE);
X
X	for (iptr=string; (temp = *iptr) ; ) {
X		temp &= 0177;			/* strips bit 7 */
X		if (isupper(temp))
X			temp |= 040;		/* set bit 5 for lower case */
X		if (temp == '/') 
X			temp=':';		/* map / into : */
X		*iptr++ = temp;
X	}
X
X	/* put in main part of name */
X	iptr=string;
X	optr=filename;
X	for (i=0; i<8; i++) {
X		if (*iptr != ' ')
X			*optr++ = *iptr++;
X	}
X
X	/* add dot if necessary */
X	if (string[8] != ' ' || string[9] != ' ' || string[10] != ' ')
X		*optr++ = '.';
X
X	/* put in extension */
X	iptr = &string[8];
X	for (i=0; i<3; i++) {
X		if (*iptr != ' ')
X			*optr++ = *iptr++;
X	}
X
X	*optr++ = '\000';
X	return (filename);
X}
X
X/* Send 11 character CP/M filename for MODEM7 batch transmission
X * Returns -1 for a protocol error; 0 if successful
X * NOTE: we tromp a little on the argument string!
X * code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xsend_name(name)
Xchar *name;
X{
X	register int cksum;
X	register char *ptr;
X
X	xmdebug("send_name");
X
X	/* append cp/m EOF */
X	name[NAMSIZ] = CTRLZ;
X	name[NAMSIZ+1] = '\000';
X
X	/* create checksum */
X	ptr = name;
X	cksum = 0;
X	while (*ptr)
X		cksum += *ptr++;
X	cksum &= 0x00FF;
X
X	/* send filename */
X
X	sendbyte(ACK);
X	ptr = name;
X	sendbyte(*ptr++);
X
X	while (*ptr) {
X
X			switch (readbyte(15)) {
X
X			case ACK: break;
X
X			case TIMEOUT: {
X				logit("Timeout while sending MODEM7 filename\n");
X				sendbyte(BAD_NAME);
X				return (-1);
X			}
X
X			default: {
X				logit("Error while sending MODEM7 filename\n");
X				sendbyte(BAD_NAME);
X				return (-1);
X			}
X		}	
X
X		sendbyte (*ptr++);
X	}
X
X	/* Check checksum returned by other side against my value */
X	if (readbyte(16) != cksum) {
X		logit("Bad checksum while sending MODEM7 filename\n");
X		sendbyte(BAD_NAME);
X		return (-1);
X	}
X
X	sendbyte(ACK);
X	return (0);
X}
X
X/* Convert Unix filename to 11 character CP/M file name (8 char name,
X * 3 char extension, dot in between is not included).
X * map ':' into '/'; Use filename to hold name.
X * code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xchar *
Xunix_cpm(string)
Xchar *string;
X{
X	register char *iptr, *optr, temp;
X	int i;
X
X	char *rindex();
X	char *strcpy();
X
X	/* blank 11 character name */
X	(void) strcpy (filename,"           ");
X
X	/* strip off any path name */
X	if ((iptr = rindex(string,'/')))
X		iptr++;
X	else
X		iptr=string;
X
X	/* skip leading '.'s */
X	while (*iptr == '.')
X		iptr++;
X
X	/* copy main part of name */
X	optr = filename;
X	i = 8;
X	while ((i--) && (*iptr) && (*iptr != '.'))
X		*optr++ = *iptr++;
X
X	/* advance to unix extension, or end of unix name */
X	while ((*iptr != '.') && (*iptr))
X		iptr++;
X
X	/* skip over the  '.' */
X	while (*iptr == '.')
X		iptr++;
X
X	/* copy extension */
X	optr = &filename[8];
X	i=3;
X	while ((i--) && (*iptr) && (*iptr != '.'))
X		*optr++ = *iptr++;
X
X	filename[NAMSIZ] = '\000';
X
X	/* Fuss with name */
X	for (iptr=filename; (temp = *iptr) ;) {
X		temp &= 0177;			/* strip bit 7 (parity bit) */
X		if (islower(temp))
X			temp &= ~040;		/* make upper case */
X		if (temp == ':')
X			temp ='/';		/* map ':' into '/' */
X		*iptr++ = temp;
X	}
X
X	if (DEBUG)
X		fprintf (LOGFP, "DEBUG: File %s sent as %s\n", string, filename);
X
X	return(filename);
X}
SHAR_EOF
chmod 0644 batch.c || echo "restore of batch.c fails"
echo "x - extracting getput.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > getput.c &&
X/*
X * Contains system routines to get and put bytes, change tty modes, etc
X * Most of the routines are VERY 4.2BSD Specific!!!
X */
X
X#include "xmodem.h"
X
X/*
X *
X *	Get a byte from the specified file.  Buffer the read so we don't
X *	have to use a system call for each character.
X *
X */
Xgetbyte(fildes, ch)				/* Buffered disk read */
Xint fildes;
Xchar *ch;
X
X	{
X	static char buf[BUFSIZ];	/* Remember buffer */
X	static char *bufp = buf;	/* Remember where we are in buffer */
X	
X	if (nbchr == 0)			/* Buffer exausted; read some more */
X		{
X		if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
X			error("File Read Error", TRUE);
X		bufp = buf;		/* Set pointer to start of array */
X		}
X	if (--nbchr >= 0)
X		{
X		*ch = *bufp++;
X		return(0);
X		}
X	else
X		{
X		return(EOF);
X		}
X	}
X
X/* Count the number of newlines in a file so we know the REAL file size */
X
Xlong
Xcountnl(fd)
Xint fd;
X{
X	char buf[BUFSIZ];
X	char *bufp;
X	long nltot = 0;
X	int numchar;
X	long lseek();
X
X	while (numchar = read(fd, buf, BUFSIZ))		/* cycle through file */
X		for (bufp=buf; numchar--; bufp++)
X			if (*bufp == '\n')
X				nltot++;
X
X	(void) lseek (fd, 0l, 0);			/* rewind file */
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: countnl--%ld newlines counted\n", nltot);
X	return (nltot);
X}
X
X/*   CRC-16 constant array...
X     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
X     (ihnp4!umn-cs!hyper!mark)
X*/
X
X/* crctab as calculated by initcrctab() */
Xunsigned short crctab[1<<B] = { 
X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
X    };
X
X/* get a byte from data stream -- timeout if "seconds" elapses */
X/* This routine is VERY 4.2 specific */
X
Xint
Xreadbyte(seconds)
Xint seconds;
X	{
X	int readfd;
X	char c;
X	struct timeval tmout;
X
X	tmout.tv_sec = seconds;
X	tmout.tv_usec = 0;
X
X	readfd = 1<<0;
X
X	if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
X		return(TIMEOUT);
X
X	read(0, &c, 1);
X
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: readbyte %02xh\n", c & 0xff);
X
X	return(c & 0xff);  /* return the char */
X	}
X
X/* flush input stream by reading pending characters */
X
Xflushin()
X	{
X	int readfd;
X	char inbuf[BBUFSIZ];
X	struct timeval tmout;
X
X	/* set up a usec timeout on stdin */
X	tmout.tv_sec = 0;
X	tmout.tv_usec = 1;
X	readfd = 1<<0;
X
X	/* any characters pending?; return if none */
X	if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
X		return;
X
X	/* read the characters to flush them (assume there are fewer than BBUFSIZ */
X	(void) read(0, inbuf, BBUFSIZ);
X	}
X
X/* 
X get a buffer (length bufsize) from data stream -- timeout if "seconds" elapses.
X Read bunches of characters to save system overhead;
X Further process data while kernel is reading stream (calculating "checksum").
X Try to nap long enough so kernel collects 100 characters or so until we wake up
X unless TOOBUSY is set.
X*/
X
X/* This routine is VERY 4.2 specific */
X
Xint
Xreadbuf(bufsize, seconds, tmode, amode, recvsectcnt, checksum, bufctr)
X
Xint bufsize,	/* number of chars to be read */
Xseconds, 	/* timeout period for each read */
Xtmode, 		/* transmission mode: TRUE if text */
Xamode, 		/* transmission mode: TRUE if apple macintosh */
X*checksum, 	/* pointer to checksum value */
X*bufctr;	/* length of actual data string in buffer */
Xlong recvsectcnt;	/* running sector count (128 byte sectors) */
X
X{
X	int readfd;		/* mask for select call */
X	struct timeval tmout;	/* timeout structure for select */
X	int numread;		/* number of chars read */
X	int left;		/* number of chars left to read */
X	int recfin = FALSE;		/* flag that EOF read */
X	char inbuf[BBUFSIZ];	/* buffer for incoming packet */
X	register unsigned char c;	/* character being processed */
X	register unsigned short chksm;	/* working copy of checksum */
X	register int bfctr;	/* working copy of bufctr */
X	int j;			/* loop index */
X	char *sectdisp();
X
X	tmout.tv_sec = seconds;
X	tmout.tv_usec = 0;
X	readfd = 1<<0;
X	chksm = 0;
X	bfctr = 0;
X
X	for (left = bufsize; left > 0;) {
X
X		/* read however many chars are waiting */
X
X		if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
X			return(TIMEOUT);
X
X		numread = read(0, inbuf, left);
X		left -= numread;
X
X		if (DEBUG)
X			fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread);
X
X		/* now process part of packet we just read */
X
X		for (j =  0; j < numread; j++) 
X			{  
X				buff[bfctr] = c = inbuf[j] & 0xff;
X				fileread++;
X
X				if (CRCMODE)  /* CRC */
X					chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
X
X				else        /* checksum */
X		       			chksm = ((chksm+c) & 0xff);
X
X				if (CHECKLENGTH && fileread > filelength)	/* past EOF ? */
X					continue;
X
X				if (tmode) 		/* text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == CR || c == 0)	/* skip CRs and nulls */
X						continue;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			else if (!recfin)	/* don't increment if past EOF */
X						bfctr++;
X					}
X				else if (amode) 	/* Apple macintosh text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == 0)		/* skip nulls */
X						continue;
X					else if (c == CR)	/* translate CR to LF */
X						buff[bfctr] = LF;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			if (!recfin)		/* don't increment if past EOF */
X						bfctr++;
X					}
X				else			/* binary */
X					bfctr++;
X
X		     	}	
X
X		/* go to sleep to save uneeded system calls while kernel
X		   is reading data from serial line; 
X		   fudge constant from 10000 to 9000 to avoid sleeping too long.
X		*/
X		if (left && !TOOBUSY)
X		    napms( (left<SLEEPNUM ? left:SLEEPNUM) * 9000/ttyspeed);
X
X	}
X
X	if (CHECKLENGTH && fileread >= filelength)
X		logitarg("File end from YMODEM length found in sector %s\n",
X		  sectdisp(recvsectcnt,bufsize,1));
X	*checksum = chksm;
X	*bufctr = bfctr;
X	return(0);
X}
X
X/* send a byte to data stream */
X
Xsendbyte(data)
Xchar data;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: sendbyte %02xh\n", data & 0xff);
X
X	if (write(1, &data, 1) != 1)  	/* write the byte (assume it goes NOW; no flushing needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/* send a buffer to data stream */
X
Xwritebuf(buffer, nbytes)
Xchar *buffer;
Xint  nbytes;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: writebuf (%d bytes)\n", nbytes);
X
X	if (write(1, buffer, nbytes) != nbytes)		/* write the buffer (assume no TIOCFLUSH needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/*
X * "nap" for specified time -- VERY 4.2BSD specific
X */
X
Xnapms (milliseconds)
Xint	milliseconds;
X{
X	struct	timeval	timeout;
X	int readfd;
X
X	if (milliseconds == 0)
X		return;
X	if (DEBUG)
X		fprintf (LOGFP, "DEBUG: napping for %d ms\n", milliseconds);
X	timeout.tv_sec = 0;
X	timeout.tv_usec = milliseconds * 1000;
X	readfd = 0;
X
X	(void) select(1, &readfd, (int *)0, (int *)0, &timeout);
X}
X
X 
X/* set and restore tty modes for XMODEM transfers */
X/* These routines are 4.2/v7(?) specific */
X
Xstruct sgttyb ttys, ttysnew;	/* for stty terminal mode calls */
Xstruct stat statbuf;		/* for terminal message on/off control */
X
Xint wason;			/* holds status of tty read write/modes */
Xchar *tty;			/* current tty name */
X
X
Xsetmodes()
X	{
X	char *ttyname();
X
X	int n;
X
X	extern onintr();
X
X	sleep(2);			/* let the output appear */
X	if (ioctl(0,TIOCGETP,&ttys)<0)  /* get tty params [V7] */
X		error("Can't get TTY Parameters", TRUE);
X
X	tty = ttyname(0);  /* identify current tty */
X	
X	ttysnew.sg_ispeed = ttys.sg_ispeed;	/* copy input speed */
X	ttysnew.sg_ospeed = ttys.sg_ospeed;	/* copy input speed */
X	ttysnew.sg_flags |= RAW;	/* set for RAW Mode */
X	ttysnew.sg_flags &= ~ECHO;	/* set for no echoing */
X	ttysnew.sg_flags &= ~TANDEM;	/* turn off flow control */
X
X	/* set new paramters */
X	if (ioctl(0,TIOCSETP,&ttysnew) < 0)
X		error("Can't set new TTY Parameters", TRUE);
X
X	/* Flush characters waiting for read or write */
X	n = 0;
X	if (ioctl(0,TIOCFLUSH,&n) < 0)
X		error("Can't flush terminal queue", TRUE);
X
X	/* get tty status */ 
X	if (stat(tty, &statbuf) < 0)  
X		error("Can't get your TTY Status", TRUE);
X
X	if (statbuf.st_mode & 022)	/* Need to turn messages off */
X		if (chmod(tty, (int)statbuf.st_mode & ~022) < 0)
X			error("Can't change  TTY mode", TRUE);
X		else 
X			wason = TRUE;
X	else 
X		wason = FALSE;
X
X	/* set up signal catcher to restore tty state if we are KILLed */
X
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, onintr);
X	}
X
X/* restore normal tty modes */
X
Xrestoremodes(errcall)
Xint errcall;
X	{
X	if (wason)
X		if (chmod(tty, (int)statbuf.st_mode | 022) < 0)
X			error("Can't change TTY mode", FALSE);
X	if (ioctl(0,TIOCSETP,&ttys) < 0)
X		{ if (!errcall)
X		   error("RESET - Can't restore normal TTY Params", FALSE);
X		else
X		     printf("RESET - Can't restore normal TTY Params\n");
X		}
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, SIG_DFL);
X	return;
X	}
X
X
X
X
X/* signal catcher */
Xonintr()
X	{
X	error("Kill signal; bailing out", TRUE);
X	}
X
X/* create string with a timestamp for log file */
X
Xchar *stamptime()
X{
X	char *asctime();		/* stuff to get timestamp */
X	struct tm *localtime(), *tp;
X	struct timeval tv;
X	struct timezone tz;
X
X	gettimeofday (&tv, &tz);		/* fill in timestamp */
X	tp = localtime ((time_t *)&tv.tv_sec);
X	return(asctime(tp));
X}
X
X
X
X/* get tty speed for time estimates */
X
Xgetspeed()
X	{
X	static int speedtbl[] = {0, 50, 75, 110, 134, 150, 200, 300, 600, 
X	   1200, 1800, 2400, 4800, 9600, 19200, 0};
X	if (ioctl(0,TIOCGETP,&ttys) < 0)	/* get tty structure */
X		error("Can't get TTY parameters", FALSE);
X
X	if (ttys.sg_ispeed >= 0 && ttys.sg_ispeed <= 14)
X		{
X		ttyspeed = speedtbl[ttys.sg_ispeed];
X		logitarg ("Line speed = %d bits per second\n", ttyspeed);
X		}
X	else
X		{
X		ttyspeed = 1200;
X		logit ("Can't determine line speed; assuming 1200 bps\n");
X		}
X	}
SHAR_EOF
chmod 0644 getput.c || echo "restore of getput.c fails"
echo "x - extracting getput.sysv.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > getput.sysv.c &&
X/*
X * Contains system routines to get and put bytes, change tty modes, etc
X * Sys V version.  UNTESTED!!!!!!
X */
X
X#include "xmodem.h"
X
X/*
X *
X *	Get a byte from the specified file.  Buffer the read so we don't
X *	have to use a system call for each character.
X *
X */
Xgetbyte(fildes, ch)				/* Buffered disk read */
Xint fildes;
Xchar *ch;
X
X	{
X	static char buf[BUFSIZ];	/* Remember buffer */
X	static char *bufp = buf;	/* Remember where we are in buffer */
X	
X	if (nbchr == 0)			/* Buffer exausted; read some more */
X		{
X		if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
X			error("File Read Error", TRUE);
X		bufp = buf;		/* Set pointer to start of array */
X		}
X	if (--nbchr >= 0)
X		{
X		*ch = *bufp++;
X		return(0);
X		}
X	else
X		{
X		return(EOF);
X		}
X	}
X
X/* Count the number of newlines in a file so we know the REAL file size */
X
Xlong
Xcountnl(fd)
Xint fd;
X{
X	char buf[BUFSIZ];
X	char *bufp;
X	long nltot = 0;
X	int numchar;
X	long lseek();
X
X	while (numchar = read(fd, buf, BUFSIZ))		/* cycle through file */
X		for (bufp=buf; numchar--; bufp++)
X			if (*bufp == '\n')
X				nltot++;
X
X	(void) lseek (fd, 0l, 0);			/* rewind file */
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: countnl--%ld newlines counted\n", nltot);
X	return (nltot);
X}
X
X/*   CRC-16 constant array...
X     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
X     (ihnp4!umn-cs!hyper!mark)
X*/
X
X/* crctab as calculated by initcrctab() */
Xunsigned short crctab[1<<B] = { 
X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
X    };
X
X/* get a byte from data stream -- timeout if "seconds" elapses */
X
Xint timedout;
X 
Xint
Xreadbyte(seconds)
Xint seconds;
X{
X	int force_it();
X	char c;
X	signal(SIGALRM, force_it);
X
X	timedout = 0;
X	alarm(seconds);
X	read(0, &c, 1);
X	alarm(0);
X	if (timedout)
X		return(TIMEOUT);
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: readbyte %02xh\n", c & 0xff);
X	return(c & 0xff);
X}
X
Xint
Xforce_it()
X{
X	timedout++;
X	return;
X}
X
X
X/* flush input stream */
X
Xflushin()
X	{
X/* No good way to do this without select */
X/* Perhaps....but we waste 1 second with every call!
X	while (readbyte(1) != TIMEOUT)
X		;
X*/
X	}
X
X/* 
X get a buffer (length bufsize) from data stream -- timeout if "seconds" elapses.
X Read bunches of characters to save system overhead;
X Further process data while kernel is reading stream (calculating "checksum").
X Try to nap long enough so kernel collects 100 characters or so until we wake up
X unless TOOBUSY is set.
X*/
X
X
Xint
Xreadbuf(bufsize, seconds, tmode, amode, recvsectcnt, checksum, bufctr)
X
Xint bufsize,	/* number of chars to be read */
Xseconds, 	/* timeout period for each read */
Xtmode, 		/* transmission mode: TRUE if text */
Xamode, 		/* transmission mode: TRUE if apple macintosh */
X*checksum, 	/* pointer to checksum value */
X*bufctr;	/* length of actual data string in buffer */
Xlong recvsectcnt;	/* running sector count (128 byte sectors) */
X
X{
X	int force_it();
X	int numread;		/* number of chars read */
X	int left;		/* number of chars left to read */
X	int recfin = 0;		/* flag that EOF read */
X	char inbuf[BBUFSIZ];	/* buffer for incoming packet */
X	register unsigned char c;	/* character being processed */
X	register unsigned short chksm;	/* working copy of checksum */
X	register int bfctr;	/* working copy of bufctr */
X	int j;			/* loop index */
X	char *sectdisp();
X
X	signal(SIGALRM, force_it);
X	chksm = 0;
X	bfctr = 0;
X
X	for (left = bufsize; left > 0;) {
X
X		/* read however many chars are waiting */
X		timedout = 0;
X		alarm(seconds);
X		numread = read(0, inbuf, left);
X		alarm(0);
X		if (timedout)
X			return(TIMEOUT);
X		left -= numread;
X
X		if (DEBUG)
X			fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread);
X
X		/* now process part of packet we just read */
X
X		for (j =  0; j < numread; j++) 
X			{  
X				buff[bfctr] = c = inbuf[j] & 0xff;
X				fileread++;
X
X				if (CRCMODE)  /* CRC */
X					chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
X
X				else        /* checksum */
X		       			chksm = ((chksm+c) & 0xff);
X
X				if (CHECKLENGTH && fileread > filelength)	/* past EOF ? */
X					continue;
X
X				if (tmode) 		/* text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == CR || c == 0)	/* skip CRs and nulls */
X						continue;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			else if (!recfin)	/* don't increment if past EOF */
X						bfctr++;
X					}
X				else if (amode) 	/* Apple macintosh text mode processing */
X					{
X					buff[bfctr] &= 0x7f;	/* nuke bit 8 */
X					if (c == 0)		/* skip nulls */
X						continue;
X					else if (c == CR)	/* translate CR to LF */
X						buff[bfctr] = LF;
X					else if (c == CTRLZ)	/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			if (!recfin)	/* don't increment if past EOF */
X						bfctr++;
X					}
X				else			/* binary */
X					bfctr++;
X
X		     	}	
X
X		/* go to sleep to save uneeded system calls while kernel
X		   is reading data from serial line, fudge constant from 10 to
X		   9 to avoid sleeping too long
X		*/
X		if (left && !TOOBUSY)
X			sleep ((left<SLEEPNUM ? left:SLEEPNUM) * 9/ttyspeed);
X	}
X
X	if (CHECKLENGTH && fileread >= filelength)
X		logitarg("File end from YMODEM length found in sector %s\n",
X		  sectdisp(recvsectcnt,bufsize,1));
X	*checksum = chksm;
X	*bufctr = bfctr;
X	return(0);
X}
X
X/* send a byte to data stream */
X
Xsendbyte(data)
Xchar data;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: sendbyte %02xh\n", data & 0xff);
X
X	if (write(1, &data, 1) != 1)  	/* write the byte (assume it goes NOW; no flushing needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/* send a buffer to data stream */
X
Xwritebuf(buffer, nbytes)
Xchar *buffer;
Xint  nbytes;
X	{
X	if (DEBUG)
X		fprintf(LOGFP, "DEBUG: writebuf (%d bytes)\n", nbytes);
X
X	if (write(1, buffer, nbytes) != nbytes)		/* write the buffer (assume no TIOCFLUSH needed) */
X		error ("Write error on stream", TRUE);
X	return;
X	}
X
X/* set and restore tty modes for XMODEM transfers */
X
Xstruct termio ttys;
Xstruct stat statbuf;		/* for terminal message on/off control */
X
Xint wason;			/* holds status of tty read write/modes */
Xchar *tty;			/* current tty name */
X
X
Xsetmodes()
X	{
X	char *ttyname();
X	struct termio ttysnew;
X
X	extern onintr();
X
X	sleep(2);			/* let the output appear */
X	if (ioctl(0,TCGETA,&ttys)<0)  /* get tty params */
X		error("Can't get TTY Parameters", TRUE);
X
X	tty = ttyname(0);  /* identify current tty */
X	
X	if (ioctl(0,TCGETA,&ttysnew)<0)  /* get tty params */
X		error("Can't get TTY Parameters", TRUE);
X	ttysnew.c_cc[4] = 1;		/* VMIN */
X	ttysnew.c_cc[5] = 0;		/* VTIME */
X	ttysnew.c_iflag = 0;
X	ttysnew.c_oflag = 0;
X	ttysnew.c_lflag = 0;
X	ttysnew.c_cflag &= ~CSIZE;
X	ttysnew.c_cflag |= CS8;
X	ttysnew.c_cflag &= ~PARENB;
X	if (ioctl(0,TCSETA,&ttysnew)<0)  /* set new paramters */
X		error("Can't set new TTY Parameters", TRUE);
X
X	if (stat(tty, &statbuf) < 0)  /* get tty status */ 
X		error("Can't get your TTY Status", TRUE);
X
X	if (statbuf.st_mode & 022)	/* Need to turn messages off */
X		if (chmod(tty, (int)statbuf.st_mode & ~022) < 0)
X			error("Can't change  TTY mode", TRUE);
X		else 
X			wason = TRUE;
X	else 
X		wason = FALSE;
X
X	/* set up signal catcher to restore tty state if we are KILLed */
X
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, onintr);
X	}
X
X/* restore normal tty modes */
X
Xrestoremodes(errcall)
Xint errcall;
X	{
X	if (wason)
X		if (chmod(tty, (int)statbuf.st_mode | 022) < 0)
X			error("Can't change TTY mode", FALSE);
X	if (ioctl(0,TCSETA,&ttys) < 0)
X		{ if (!errcall)
X		   error("RESET - Can't restore normal TTY Params", FALSE);
X		else
X		     printf("RESET - Can't restore normal TTY Params\n");
X		}
X	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X		signal(SIGTERM, SIG_DFL);
X	return;
X	}
X
X
X
X
X/* signal catcher */
Xonintr()
X	{
X	error("Kill signal; bailing out", TRUE);
X	}
X
X/* create string with a timestamp for log file */
X
Xchar *stamptime()
X{
X	char *asctime();		/* stuff to get timestamp */
X	struct tm *localtime(), *tp;
X	long now;
X
X	time(&now);
X	tp = localtime(&now);
X	return(asctime(tp));
X}
X
X
X
X/* get tty speed for time estimates */
X
Xgetspeed()
X	{
X	static int speedtbl[] = {0, 50, 75, 110, 134, 150, 200, 300, 600,
X	1200, 1800, 2400, 4800, 9600, 19200, 0};
X	struct termio ttystemp;
X
X	if (ioctl(0,TCGETA,&ttystemp) < 0)	/* get tty structure */
X		error("Can't get TTY parameters", FALSE);
X	if ((ttystemp.c_cflag & 017) >= 0 && (ttystemp.c_cflag & 017) <= 14)
X		{
X		ttyspeed = speedtbl[ttystemp.c_cflag & 017];
X		logitarg ("Line speed = %d bits per second\n", ttyspeed);
X		}
X	else
X		{
X		ttyspeed = 1200;
X		logit ("Can't determine line speed; assuming 1200 bps\n");
X		}
X	}
SHAR_EOF
chmod 0644 getput.sysv.c || echo "restore of getput.sysv.c fails"
echo "x - extracting misc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > misc.c &&
X#include "xmodem.h"
X
X/*  Print Help Message  */
Xhelp()
X	{
X	fprintf(stderr, "\nUsage:  \n\txmodem ");
X	fprintf(stderr, "-[rb!rt!ra!sb!st!sa][options] filename\n");
X	fprintf(stderr, "\nMajor Commands --");
X	fprintf(stderr, "\n\trb <-- Receive Binary");
X	fprintf(stderr, "\n\trt <-- Receive Text");
X	fprintf(stderr, "\n\tra <-- Receive Apple macintosh text");
X	fprintf(stderr, "\n\tsb <-- Send Binary");
X	fprintf(stderr, "\n\tst <-- Send Text");
X	fprintf(stderr, "\n\tsa <-- Send Apple macintosh text");
X	fprintf(stderr, "\nOptions --");
X	fprintf(stderr, "\n\ty  <-- Use YMODEM Batch Mode on transmit");
X	fprintf(stderr, "\n\tm  <-- Use MODEM7 Batch Mode on transmit");
X	fprintf(stderr, "\n\tk  <-- Use 1K packets on transmit");
X	fprintf(stderr, "\n\tc  <-- Select CRC mode on receive");
X	fprintf(stderr, "\n\tt  <-- Indicate a TOO BUSY Unix system");
X	fprintf(stderr, "\n\td  <-- Delete xmodem.log file before starting");
X	fprintf(stderr, "\n\tl  <-- (ell) Turn OFF Log File Entries");
X	fprintf(stderr, "\n\tx  <-- Include copious debugging information in log file");
X	fprintf(stderr, "\n");
X	}
X
X/* get type of transmission requested (text or binary) */
Xgettype(ichar)
Xchar ichar;
X	{
X	if (ichar == 't' || ichar == 'T')
X		return('t');
X	else if (ichar == 'b' || ichar == 'B')
X		return('b');
X	else if (ichar == 'a' || ichar == 'A')
X		return('a');
X	else
X		error("Invalid Send/Receive Parameter - not t or b", FALSE);
X	return('\0');
X	}
X
X/* return a string containing transmission type */
Xchar *
Xprtype(ichar)
Xchar ichar;
X	{
X	if (ichar == 't' || ichar == 'T')
X		return("text");
X	else if (ichar == 'b' || ichar == 'B')
X		return("binary");
X	else if (ichar == 'a' || ichar == 'A')
X		return("apple");
X	else
X		return("");
X	}
X
X/* print error message and exit; if mode == TRUE, restore normal tty modes */
Xerror(msg, mode)
Xchar *msg;
Xint mode;
X	{
X	if (mode)
X		restoremodes(TRUE);  /* put back normal tty modes */
X	fprintf(stderr, "\r\n%s\n", msg);
X	if ((LOGFLAG || DEBUG) && (LOGFP != NULL))
X		{   
X		fprintf(LOGFP, "XMODEM Fatal Error:  %s\n", msg);
X	    	fclose(LOGFP);
X		}
X	exit(-1);
X	}
X
X
X/* Construct a proper (i.e. pretty) sector count for messages */
X
Xchar
X*sectdisp(recvsectcnt, bufsize, plus1)
Xlong recvsectcnt;
Xint bufsize, plus1;
X	{
X	static char string[20];
X	if (plus1)
X		recvsectcnt += (bufsize == 128) ? 1 : 8;
X	if (bufsize == 128 || recvsectcnt == 0)
X		sprintf (string, "%d", recvsectcnt);
X	else
X		sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
X	return(string);
X	}
X
X/* type out debugging info */
Xxmdebug(str)
Xchar *str;
X	{
X	if (DEBUG && (LOGFP != NULL))
X		fprintf(LOGFP,"DEBUG: '%s'\n",str);
X	}
X
X/* print elapsed time and rate of transfer in logfile */
X
Xint quant[] = { 60, 60, 24};	
Xchar sep[3][10] = { "second", "minute", "hour" };
X
Xprtime (numsect, seconds)
Xlong numsect;
Xtime_t seconds;
X
X{
X	register int i;
X	register int Seconds;
X	int nums[3];
X	int rate;
X
X	if (!LOGFLAG || numsect == 0)
X		return(0);
X
X	Seconds = (int)seconds;
X	Seconds = (Seconds > 0) ? Seconds : 0;
X
X	rate = (Seconds != 0) ? 128 * numsect/Seconds : 0;
X
X	for (i=0; i<3; i++) {
X		nums[i] = (Seconds % quant[i]);
X		Seconds /= quant[i];
X	}
X
X	fprintf (LOGFP, "%ld Sectors Transfered in ", numsect);
X
X	if (rate == 0)
X		fprintf (LOGFP, "0 seconds");
X	else
X		while (--i >= 0)
X			if (nums[i])
X				fprintf (LOGFP, "%d %s%c ", nums[i], &sep[i][0],
X					nums[i] == 1 ? ' ' : 's');
X	fprintf (LOGFP, "\n");
X
X	if (rate != 0)
X		fprintf (LOGFP, "Transfer Rate = %d Characters per Second\n", rate);
X
X	return(0);
X}
X
X/* Print elapsed time estimate */
X
Xprojtime (numsect, fd)
Xlong numsect;
XFILE *fd;
X	{
X	register int i;
X	register int seconds;
X	int nums[3];
X
X	if (numsect == 0)
X		return (0);
X
X/* constant below should really be 1280; reduced to 90% to account for time lost in overhead */
X
X	seconds = 1422 * numsect / ttyspeed + 1;
X
X	for (i=0; i<3; i++) {
X		nums[i] = (seconds % quant[i]);
X		seconds /= quant[i];
X	}
X
X	fprintf (fd, "Estimated transmission time ");
X
X	while (--i >= 0)
X		if (nums[i])
X			fprintf (fd, "%d %s%c ", nums[i], &sep[i][0],
X				nums[i] == 1 ? ' ' : 's');
X	fprintf (fd, "\n");
X	return (0);
X	}
SHAR_EOF
chmod 0644 misc.c || echo "restore of misc.c fails"
echo "x - extracting receive.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > receive.c &&
X#include "xmodem.h"
X
X/**  receive a file  **/
X
X/* returns TRUE if in the midst of a batch transfer */
X/* returns FALSE if no more files are coming */
X
X/* This routine is one HUGE do-while loop with far to many indented levels.
X * I chose this route to facilitate error processing and to avoid GOTOs.
X * Given the troubles I've had keeping the nested IF statements straight,
X * I was probably mistaken...
X */
X
Xrfile(name)
Xchar *name;
X{
X
Xchar *sectdisp();
Xchar *cpm_unix();
Xchar *strcpy();
Xchar *ctime();
Xtime_t time();
X
Xint fd,     /* file descriptor for created file */
Xchecksum,   /* packet checksum */
Xfirstchar,  /* first character of a packet */
Xsectnum,    /* number of last received packet (modulo 128) */
Xsectcurr,   /* second byte of packet--should be packet number (mod 128) */
Xsectcomp,   /* third byte of packet--should be complement of sectcurr */
Xtmode,      /* text mode if true */
Xamode,      /* apple mode if true */
Xerrors,     /* count of errors for each packet */
Xsterrors,   /* count of errors during startup handshake */
Xerrorflag,  /* set true when packet (or first char of putative packet) is invalid */
Xfatalerror, /* set within main "read-packet" Do-While when bad error found */
Xinchecksum, /* incoming checksum or CRC */
Xexpsect,    /* expected number of sectors (YMODEM batch) */
Xfirstwait,  /* seconds to wait for first character in a packet */
Xbufsize;    /* packet size (128 or 1024) */
Xlong recvsectcnt;   /* running sector count (128 byte sectors) */
Xlong modtime;       /* Unix style file mod time from YMODEM header */
Xint filemode;       /* Unix style file mode from YMODEM header */
Xlong readbackup;    /* "backup" value for characters read in file */
Xtime_t timep[2];    /* used in setting mod time of received file */
Xchar *p;    /* generic pointer */
Xint bufctr; /* number of real chars in read packet */
Xunsigned char *nameptr; /* ptr in filename for MODEM7 protocol */
Xtime_t start;       /* starting time of transfer */
Xint openflag = FALSE;   /* is file open for writing? */
X
Xlogit("----\nXMODEM File Receive Function\n");
Xif (CRCMODE)
Xlogit("CRC mode requested\n");
X
XBATCH = FALSE;          /* don't know if really are in batch mode ! */
Xfatalerror = FALSE;
Xfirstwait = WAITFIRST;  /* For first packet, wait short time */
Xsectnum = errors = recvsectcnt = 0;
Xbufsize = 128;
Xmodtime = 0l; filemode = 0;
Xfilelength = 0l; fileread =0l; CHECKLENGTH = FALSE;
X
Xtmode = (XMITTYPE == 't') ? TRUE : FALSE;
Xamode = (XMITTYPE == 'a') ? TRUE : FALSE;
X
X/* start up transfer */
X
Xsterrors = 0;
Xflushin();         /* flush input queue */
X
Xif (CRCMODE)        
X{
X	sendbyte(CRCCHR);
X	if (LONGPACK && !MDM7BAT)
X		sendbyte(KCHR);
X}
Xelse
X	sendbyte(NAK);
X
X
Xdo                  /* start of MAIN Do-While loop to read packets */
X{   
X	errorflag = FALSE;
X	do              /* start by reading first byte in packet */
X	{
X		firstchar = readbyte(firstwait);
X	} 
X	while ((firstchar != SOH) 
X	    && (firstchar != STX) 
X	    && (firstchar != EOT) 
X	    && (firstchar != ACK || recvsectcnt > 0) 
X	    && (firstchar != TIMEOUT) 
X	    && (firstchar != CAN || recvsectcnt > 0));
X
X	if (firstchar == EOT)           /* check for REAL EOT */
X	{
X		flushin();
X		sendbyte(NAK);              /* NAK the EOT */
X		if ((firstchar = readbyte(3)) != EOT)   /* check next character */
X		{
X			logit("Spurious EOT detected; ignored\n");
X			if ((firstchar == SOH) || (firstchar == STX) ||
X			    (firstchar == ACK && recvsectcnt == 0) ||
X			    (firstchar == CAN && recvsectcnt == 0) ||
X			    (firstchar == TIMEOUT))
X				break;
X			else
X			{
X				firstchar = 0;
X				errorflag = TRUE;
X			}
X		}
X	}
X
X	if (firstchar == TIMEOUT)       /* timeout? */
X	{  
X		if (recvsectcnt > 0)
X			logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
X		errorflag = TRUE;
X	}
X
X	if (firstchar == CAN)           /* bailing out? (only at beginning) */
X	{
X		if ((readbyte(3) & 0x7f) == CAN)
X			error("Reception canceled at user's request",TRUE);
X		else
X		{
X			errorflag = TRUE;
X			logit("Received single CAN character\n");
X		}
X	}
X
X	if (firstchar == ACK)           /* MODEM7 batch? (only at beginning) */
X	{
X		int i,c; 
X
X		logit("MODEM7 Batch Protocol\n");
X		nameptr = buff;
X		checksum = 0;
X
X		for (i=0; i<NAMSIZ; i++)
X		{
X			c = readbyte(3);
X
X			if (c == CAN)
X			{
X				if (readbyte(3) == CAN)
X					error("Program Canceled by User", TRUE);
X				else
X				{
X					logit("Received single CAN character in MODEM7 filename\n");
X					errorflag = TRUE;
X					break;
X				}
X			}
X
X			if (c == EOT && i == 0)
X			{
X				sendbyte(ACK);          /* acknowledge EOT */
X				logit("MODEM7 Batch Receive Complete\n");
X				return (FALSE);
X			}
X
X			if (c == TIMEOUT)
X			{
X				logit("Timeout waiting for MODEM7 filename character\n");
X				errorflag = TRUE;
X				break;
X			}
X
X			if (c == BAD_NAME)
X			{
X				logit("Error during MODEM7 filename transfer\n");
X				errorflag = TRUE;
X				break;
X			}
X
X			*nameptr++ = c;
X			checksum += c;
X			sendbyte(ACK);
X		}
X
X		if (!errorflag)
X		{
X			c = readbyte(3);
X			if (c == CTRLZ)     /* OK; end of string found */
X			{
X				sendbyte(checksum + CTRLZ);
X				if (readbyte(15) == ACK)     /* file name found! */
X				{
X					xmdebug("MODEM7 file name OK");
X					*nameptr = '\000';  /* unixify the file name */
X					name = cpm_unix(buff);
X					BATCH = TRUE;
X					logitarg("MODEM7 file name: %s\n", name);
X					errors = 0;     /* restart crc handshake */
X					sleep(2);       /* give other side a chance */
X				}
X				else
X				{
X					logit("Checksum error in MODEM7 filename\n");
X					errorflag = TRUE;
X				}
X			}
X			else
X			{
X				logit("Length error in MODEM7 filename\n");
X				errorflag = TRUE;
X			}
X		}
X	}
X
X
X	if (firstchar == SOH || firstchar == STX)  /* start reading packet */
X	{
X		bufsize = (firstchar == SOH) ? 128 : 1024;
X
X		if (recvsectcnt == 0)           /* 1st data packet, initialize */
X		{
X			if (bufsize == 1024)
X				logit("1K packet mode chosen\n");
X			start = time((time_t *) 0);
X			errors = 0;
X			firstwait = 5;
X		}
X
X		sectcurr = readbyte(3);
X		sectcomp = readbyte(3);
X		if ((sectcurr + sectcomp) == 0xff)  /* is packet number checksum correct? */
X		{  
X			if (sectcurr == ((sectnum+1) & 0xff))   /* is packet number correct? */
X			{  
X				if (DEBUG)
X					fprintf(LOGFP,"DEBUG: packet %d started\n", sectnum);
X
X				/* Read, process and calculate checksum for a buffer of data */
X
X				readbackup = fileread;
X				if (readbuf(bufsize, 1, tmode, amode, recvsectcnt, &checksum, &bufctr) != TIMEOUT) 
X				{
X
X					/* verify checksum or CRC */
X
X					if (CRCMODE) 
X					{
X						checksum &= 0xffff;
X						inchecksum = readbyte(3);  /* get 16-bit CRC */
X						inchecksum = (inchecksum<<8) | readbyte(3);
X					}
X
X					else
X						inchecksum = readbyte(3);  /* get simple 8-bit checksum */
X
X					if (inchecksum == checksum) /* good checksum, hence good packet */
X					{  
X						xmdebug("checksum ok");
X						errors = 0;
X						recvsectcnt += (bufsize == 128) ? 1 : 8;
X						sectnum = sectcurr; 
X
X						if (!openflag)      /* open output file if necessary */
X						{
X							openflag = TRUE;
X							if ((fd = creat(name, CREATMODE)) < 0)
X							{
X								sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X								error("Can't create file for receive", TRUE);
X							}
X							if (!BATCH)
X								logitarg("File Name: %s\n", name);
X						}
X
X						if (write(fd, (char *) buff, bufctr) != bufctr)
X						{
X							close(fd);
X							unlink(name);
X							error("File Write Error", TRUE);
X						}
X						else
X						{
X							flushin();          /* flush input */
X							sendbyte(ACK);      /* ACK the received packet */
X						}
X					}
X
X					/* Start handling various errors and special conditions */
X
X					else        /* bad checksum */
X					{  
X						logitarg("Checksum Error on Sector %s:  ", sectdisp(recvsectcnt,bufsize,1));
X						logitarg("sent=%x  ", inchecksum);
X						logitarg("recvd=%x\n", checksum);
X						fileread = readbackup;
X						errorflag = TRUE;
X					}
X				}
X
X				else    /* read timeout */
X				{
X					logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
X					fileread = readbackup;
X					errorflag = TRUE;
X				}
X			}
X
X			else        /* sector number is wrong OR Ymodem filename */
X			{ 
X				if (sectcurr == 0 && recvsectcnt == 0)  /* Ymodem file-name packet */
X				{
X					logit("YMODEM Batch Protocol\n");
X
X					/* Read and process a file-name packet */
X
X					if (readbuf(bufsize, 1, FALSE, FALSE, recvsectcnt, &checksum, &bufctr) != TIMEOUT) 
X					{
X
X						/* verify checksum or CRC */
X
X						if (CRCMODE) 
X						{
X							checksum &= 0xffff;
X							inchecksum = readbyte(3);  /* get 16-bit CRC */
X							inchecksum = (inchecksum<<8) | readbyte(3);
X						}
X
X						else
X							inchecksum = readbyte(3);  /* get simple 8-bit checksum */
X
X						if (inchecksum == checksum) /* good checksum, hence good filename */
X						{
X							xmdebug("checksum ok");
X							strcpy(name, (char *)buff);
X							expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]);
X							BATCH = TRUE;
X							YMDMBAT = TRUE;
X							if (strlen(name) == 0)  /* check for no more files */
X							{
X								flushin();          /* flush input */
X								sendbyte(ACK);      /* ACK the packet */
X								logit("YMODEM Batch Receive Complete\n");
X								return (FALSE);
X							}
X							unixify(name);       /* make filename canonical */
X
X							/* read rest of YMODEM header */
X							p = (char *)buff + strlen((char *)buff) + 1;
X							sscanf(p, "%ld%lo%o", &filelength, &modtime, &filemode);
X							logitarg("YMODEM file name: %s\n", name);
X							fileread = 0l;
X							if (filelength)
X							{
X								CHECKLENGTH = TRUE;
X								logitarg("YMODEM file size: %ld\n", filelength);
X							}
X							else if (expsect)
X								logitarg("YMODEM estimated file length %d sectors\n", expsect);
X							if (modtime)
X							{
X								logitarg("YMODEM file date: %s", ctime(&modtime));
X							}
X							if (filemode)
X								logitarg("YMODEM file mode: %o", filemode);
X
X							sendbyte(ACK);      /* ACK the packet */
X							firstwait = WAITFIRST;  /* reset to negotiate */
X						}
X
X						else                /* bad filename checksum */
X						{
X							logit("checksum error on filename sector\n");
X							errorflag = TRUE;
X						}
X					}
X					else
X					{
X						logit("Timeout while reading filename packet\n");
X						errorflag = TRUE;
X					}
X				}
X
X				else if (sectcurr == sectnum)   /* duplicate sector? */
X				{  
X					logitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
X					flushin();                  /* REALLY flush input */
X					while(readbyte(1) != TIMEOUT)
X						;
X					sendbyte(ACK);
X				}
X				else                /* no, real phase error */
X				{
X					logitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
X					errorflag = TRUE;
X					fatalerror = TRUE;
X				}
X			}
X		}
X
X		else        /* bad packet number checksum */
X		{  
X			logitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
X			errorflag = TRUE;
X		}
X
X	}           /* END reading packet loop */
X
X	if (errorflag && !fatalerror && recvsectcnt != 0)   /* Handle errors */
X	{  
X		errors++;
X
X		if (errors >= ERRORMAX)     /* over error limit? */
X			fatalerror = TRUE;
X		else                        /* flush input and NAK the packet */
X		{
X			flushin();
X			while (readbyte(1) != TIMEOUT)  /* wait for line to settle */
X				;
X			sendbyte(NAK);
X		}
X	}
X
X	if (recvsectcnt == 0 && errorflag && firstchar != EOT) 	/* handle startup handshake */
X	{
X		sterrors++;
X
X		if (sterrors >= STERRORMAX)
X			fatalerror = TRUE;
X
X		else if (CRCMODE && sterrors == CRCSWMAX && !YMDMBAT)
X		{
X			CRCMODE = FALSE;
X			logit("Sender not accepting CRC request, changing to checksum\n");
X			sendbyte(NAK);
X		}
X
X		else if (!CRCMODE && sterrors == CRCSWMAX && !YMDMBAT)
X		{
X			CRCMODE = TRUE;
X			logit("Sender not accepting checksum request, changing to CRC\n");
X			sendbyte(CRCCHR);
X			if (LONGPACK && !MDM7BAT)
X				sendbyte(KCHR);
X		}
X
X		else if (CRCMODE)
X			{
X			sendbyte(CRCCHR);
X			if (LONGPACK && !MDM7BAT)
X				sendbyte(KCHR);
X			}
X
X		else
X			sendbyte(NAK);
X	}
X}
Xwhile ((firstchar != EOT) && !fatalerror);   /* end of MAIN Do-While */
X
Xif ((firstchar == EOT) && !fatalerror)  /* normal exit? */
X{
X	if (openflag)       /* close the file */
X		close(fd);
X	sendbyte(ACK);      /* ACK the EOT */
X	logit("Receive Complete\n");
X	prtime (recvsectcnt, time((time_t *) 0) - start);
X
X	if (openflag && modtime)   /* set file modification time */
X	{
X		timep[0] = time((time_t *) 0);
X		timep[1] = modtime;
X		utime(name, timep);
X	}
X
X	if (BATCH)          /* send appropriate return code */
X		return(TRUE);
X	else
X		return(FALSE);
X}
Xelse                /* no, error exit */
X{ 
X	if (openflag)
X	{
X		sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X		close(fd);
X		unlink(name);
X		error("ABORTED -- Too Many Errors--deleting file", TRUE);
X	}
X	else if (recvsectcnt != 0)
X		error("ABORTED -- Too Many Errors", TRUE);
X	else
X		error("ABORTED -- Remote system is not responding", TRUE);
X}
Xreturn(FALSE);
X
X}
SHAR_EOF
chmod 0644 receive.c || echo "restore of receive.c fails"
echo "x - extracting send.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > send.c &&
X/**  send a file  **/
X
X/*
X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
X *
X * If "name" is NULL; close out the BATCH send.
X */
X
X#include "xmodem.h"
X
Xsfile(name)
Xchar *name;
X	{
X
X	char *sectdisp();
X	time_t time();
X	char *strcpy();
X	char *unix_cpm();
X	char *cpmify();
X	long countnl();
X
X	extern unsigned short crctab[1<<B];	/* CRC-16 constant values, see getput.c */
X
X	register int bufctr, 		/* array index for data buffer */
X	sectnum;			/* packet number for packet header */
X
X	register unsigned short checksum; 	/* checksum/crc */
X
X	char blockbuf[BBUFSIZ+6];	/* holds packet as it is constructed */
X
X	struct stat filestatbuf;	/* file status info */
X
X	int fd, 		/* file descriptor for file being transmitted */
X	attempts,		/* number of attempts made to transmit a packet */
X	nlflag, 		/* flag that we have to send a LF in next packet */
X	sendfin, 		/* flag that we are sending the last packet */
X	closeout,		/* flag that we are closing out batch send */
X	startup,		/* flag that we are starting batch send */
X	tmode,			/* TRUE for text mode */
X	amode,			/* TRUE for apple mode */
X	filepack,		/* TRUE when sending first packet */
X	buf1024,		/* TRUE when sending 1K packets */
X	bbufcnt,		/* array index for packet */
X	firstchar,		/* first character in protocol transaction */
X	bufsize,		/* packet size (128 or 1024) */
X	sendresp;  		/* response char to sent block received from remote*/
X	long sentsect;		/* count of 128 byte sectors actually sent */
X	long expsect;		/* count of 128 byte sectors expected to be sent */
X	time_t start;		/* starting time of transfer */
X	char c;
X
X	nbchr = 0;  /* clear buffered read char count */
X
X	CRCMODE = FALSE;	/* Receiver determines use of crc or checksum */
X
X	buf1024 = LONGPACK;	/* set packet size flag to command line switch */
X
X	closeout = FALSE; startup = TRUE; filepack = FALSE;	/* indicate state of batch transfer */
X
X	tmode = (XMITTYPE == 't') ? TRUE : FALSE;	/* set text mode */
X	amode = (XMITTYPE == 'a') ? TRUE : FALSE;	/* set apple mode */
X
X	/* Check on NULL file name */
X	if (strcmp(name,"") == 0)
X		{
X		if (BATCH)
X			closeout = TRUE;
X		else
X			{
X			sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X			error("NULL file name in send", TRUE);
X			}
X		}
X
X	if (!closeout)		/* Are we closing down batch? */
X		{			/* no; let's send a file */
X		logit("----\nXMODEM Send Function\n");
X
X		if ((fd = open(name, 0)) < 0)	
X			{  
X			sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X     	   		error("Can't open file for send", TRUE);
X			}
X	
X		stat(name, &filestatbuf);  /* get file status bytes */
X		if (tmode)		   /* count up NLs */
X			filestatbuf.st_size += countnl(fd);
X		expsect = (filestatbuf.st_size/128) + 1;
X	
X		if (LOGFLAG)
X			{   
X		    	fprintf(LOGFP, "File Name: %s\n", name);
SHAR_EOF
echo "End of part 1"
echo "File send.c is continued in part 2"
echo "2" > s2_seq_.tmp
exit 0
-- 
Keith Petersen
Arpa: W8SDZ@SIMTEL20.ARPA
Uucp: {bellcore,decwrl,harvard,lll-crg,ucbvax,uw-beaver}!simtel20.arpa!w8sdz
GEnie: W8SDZ

--
Dick Flanagan, vacation moderator of comp.binaries.ibm.pc
{backbones}!ucbvax!ucscc!slvblc!dick  or  slvblc!dick@ucscc.ucsc.edu