v13i094: Full featured xmodem program, v3.4, Part02/03

Rich Salz rsalz at bbn.com
Fri Mar 4 22:59:34 AEST 1988


Submitted-by: Steve Grandi <grandi at noao.arizona.edu>
Posting-number: Volume 13, Issue 94
Archive-name: xmodem3.4/part02

: This is a shar archive.  Extract with sh, not csh.
echo x - getput.c
sed -e 's/^X//' > getput.c << '!Funky!Stuff!'
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/*   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/* 
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, recvsectcnt, checksum, bufctr)
X
Xint bufsize,	/* number of chars to be read */
Xseconds, 	/* timeout period for each read */
Xtmode, 		/* transmission mode: TRUE if text, FALSE if binary */
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
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					if (c == CTRLZ)		/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			if (!recfin)	/* dont 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	}
!Funky!Stuff!
echo x - getput.sysv.c
sed -e 's/^X//' > getput.sysv.c << '!Funky!Stuff!'
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/*   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 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, recvsectcnt, checksum, bufctr)
X
Xint bufsize,	/* number of chars to be read */
Xseconds, 	/* timeout period for each read */
Xtmode, 		/* transmission mode: TRUE if text, FALSE if binary */
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
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					if (c == CTRLZ)		/* CP/M EOF char */
X						{  
X						recfin = TRUE;
X		       				continue;
X		       				}
X		       			if (!recfin)	/* dont 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 [V7] */
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	}
!Funky!Stuff!
echo x - send.c
sed -e 's/^X//' > send.c << '!Funky!Stuff!'
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
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; FALSE for binary mode */
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	extrachar;		/* count of extra LF characters added */
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	closeout = FALSE; startup = TRUE;	/* indicate state of batch transfer */
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		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		expsect = (filestatbuf.st_size/128) + 1;
X	
X		if (LOGFLAG)
X			{   
X			fprintf(LOGFP, "----\nXMODEM Send Function\n");
X		    	fprintf(LOGFP, "File Name: %s\n", name);
X		  	fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
X		  	  (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size);
X			projtime(expsect, LOGFP);
X			}
X		}
X	else
X		{
X		logit("----\nXMODEM Send Function\n");
X		logit("Closing down Batch Transmission\n");
X		}
X
X
X	tmode = (XMITTYPE == 't') ? TRUE : FALSE;	/* set text mode */
X
X	bufsize = LONGPACK ? 1024 : 128;		/* set sector size */
X	if (LONGPACK && !closeout)
X		logit("1K packet mode chosen\n");
X
X        sendfin = nlflag = FALSE;
X  	attempts = 0;
X
X	/* wait for and read startup character */
Xrestart:
X	do
X		{
X		while (((firstchar=readbyte(1)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN))
X			if (++attempts > NAKMAX)
X				{
X				if (MDM7BAT && startup)
X					{
X					sendbyte(ACK); sendbyte(EOT);
X					}
X				error("Remote System Not Responding", TRUE);
X				}
X
X		if ((firstchar & 0x7f) == CAN)
X			if (readbyte(3) == CAN)
X				error("Send cancelled at user's request",TRUE);
X
X		if (firstchar == CRCCHR)
X			{
X			CRCMODE = TRUE;
X			if (!closeout)
X				logit("CRC mode requested\n");
X			if (readbyte(1) == KCHR)
X				{
X				LONGPACK = TRUE;
X				logit("Receiver invoked 1K packet mode\n");
X				}
X			}
X		}
X	while (firstchar != NAK && firstchar != CRCCHR);
X
X	if (MDM7BAT && closeout)	/* close out MODEM7 batch */
X		{
X		sendbyte(ACK); sendbyte (EOT);
X		readbyte(2);			/* flush junk */
X		return;
X		}
X
X	if (MDM7BAT && startup)		/* send MODEM7 file name */
X		{
X		if (send_name(unix_cpm(name)) == -1)
X			{
X			attempts = 0;
X			goto restart;
X			}
X		startup = FALSE;
X		attempts = 0;
X		goto restart;
X		}
X
X	sectnum = 1;
X
X	if (YMDMBAT)	/* Fudge for YMODEM transfer (to send name packet) */
X		{
X		sectnum = 0;
X		bufsize = 128;
X		}
X
X	attempts = sentsect = extrachar = 0;
X	start = time((time_t *) 0);
X
X        do 			/* outer packet building/sending loop; loop till whole file is sent */
X		{   
X
X		if (closeout && YMDMBAT && sectnum == 1)	/* close out YMODEM */
X			return;
X
X		if (YMDMBAT && sectnum == 1)			/* get set to send YMODEM data packets */
X			{
X			bufsize = LONGPACK ? 1024 : 128;
X			do
X				{
X				while (((firstchar=readbyte(3)) != CRCCHR) && (firstchar != CAN))
X					if (++attempts > STERRORMAX)
X						error("YMODEM protocol botch, C expected", TRUE);
X				if ((firstchar&0x7f) == CAN)
X					if (readbyte(3) == CAN)
X						error("Send cancelled at User's request", TRUE);
X				}
X			while (firstchar != CRCCHR);
X			attempts = 0;
X			}
X
X		if (extrachar >= 128)	/* update expected sector count */
X			{
X			extrachar = 0;
X			expsect++;
X			}
X
X		if ((bufsize == 1024) && (attempts > KSWMAX))
X			{
X			logit("Reducing packet size to 128 due to excessive errors\n");
X			bufsize = 128;
X			}
X
X		if ((bufsize == 1024) && ((expsect - sentsect) < 8))
X			{
X			logit("Reducing packet size to 128 for tail end of file\n");
X			bufsize = 128;
X			}
X
X		if (sectnum > 0)	/* data packet */
X			{
X			for (bufctr=0; bufctr < bufsize;)
X	    			{
X				if (nlflag)
X	       	 			{  
X					buff[bufctr++] = LF;  /* leftover newline */
X	       	    			nlflag = FALSE;
X	        			}
X				if (getbyte(fd, &c) == EOF)
X					{ 
X					sendfin = TRUE;  /* this is the last sector */
X		   			if (!bufctr)  /* if EOF on sector boundary */
X		      				break;  /* avoid sending extra sector */
X		      			buff[bufctr++] = CTRLZ;  /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */
X		   			continue;
X		      			}
X	
X				if (tmode && c == LF)  /* text mode & Unix newline? */
X		    			{
X					extrachar++;
X					buff[bufctr++] = CR;  /* insert carriage return */
X			     		if (bufctr < bufsize)
X		                		buff[bufctr++] = LF;  /* insert LF */
X		 	      		else
X			        		nlflag = TRUE;  /* insert on next sector */
X		   			}	
X				else
X					buff[bufctr++] = c;  /* copy the char without change */
X		    		}
X
X	    		if (!bufctr)  /* if EOF on sector boundary */
X   	       			break;  /* avoid sending empty sector */
X			}	
X
X		else		/* YMODEM filename packet */
X			{
X			for (bufctr=0; bufctr<bufsize; bufctr++)  /* zero packet */
X				buff[bufctr]=0;
X			if (!closeout)
X				{
X				cpmify(name);
X				strcpy((char *)buff, name);
X				if (!tmode)	/* put in file length etc. only if binary transfer */
X					{
X					register char *p;
X					p = (char *)buff + strlen(name) + 1;
X					sprintf(p, "%lu %lo %o", filestatbuf.st_size, 
X					  filestatbuf.st_mtime, filestatbuf.st_mode);
X					logitarg("YMODEM header information: %s\n", p);
X					}
X				buff[bufsize-2]	= (expsect & 0xff);        /* put in KMD kludge information */
X				buff[bufsize-1] = ((expsect >> 8) & 0xff);
X				}
X			}
X
X		bbufcnt = 0;		/* start building block to be sent */
X		blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;    /* start of packet char */
X		blockbuf[bbufcnt++] = sectnum;	    /* current sector # */
X		blockbuf[bbufcnt++] = ~sectnum;   /* and its complement */
X
X               	checksum = 0;  /* initialize checksum */
X               	for (bufctr=0; bufctr < bufsize; bufctr++)
X       			{
X			blockbuf[bbufcnt++] = buff[bufctr];
X
X			if (CRCMODE)
X				checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]];
X
X			else
X               			checksum = ((checksum+buff[bufctr]) & 0xff);
X         		}
X
X		if (CRCMODE)		/* put in CRC */
X			{
X			checksum &= 0xffff;
X			blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
X			blockbuf[bbufcnt++] = (checksum & 0xff);
X			}
X		else			/* put in checksum */
X			blockbuf[bbufcnt++] = checksum;
X
X            	attempts = 0;
X	
X            	do				/* inner packet loop */
X            		{
X
X			writebuf(blockbuf, bbufcnt);	/* write the block */
X
X			if (DEBUG)
X				fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", 
X				bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff);
X
X                	attempts++;
X			sendresp = readbyte(10);  /* get response from remote */
X
X			if (sendresp != ACK)
X		   		{
X				if (sendresp == TIMEOUT)
X					{
X		   			logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1));
X					}
X				else if (sendresp == NAK)
X					{
X		   			logitarg("NAK on sector %s\n",sectdisp(sentsect,bufsize,1));
X					}
X				else
X					{
X		   			logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1));
X					}
X		   		}
X            		}
X			while((sendresp != ACK) && (attempts < ERRORMAX));	/* close of inner loop */
X
X       		sectnum++;  /* increment to next sector number */
X		sentsect += (bufsize == 128) ? 1 : 8;
X    		}
X		while (!sendfin && ( attempts < ERRORMAX));	/* end of outer loop */
X
X	if (attempts > ERRORMAX)
X		{
X		sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X		error ("Too many errors in transmission", TRUE);
X		}
X
X    	attempts = 0;
X    	sendbyte(EOT);  /* send 1st EOT to close down transfer */
X	
X    	while ((readbyte(15) != ACK) && (attempts++ < EOTMAX)) 	/* wait for ACK of EOT */
X		{
X		if (attempts > 1)
X			logitarg("EOT not ACKed, try %d\n", attempts);
X	   	sendbyte(EOT);
X		}
X
X    	if (attempts >= RETRYMAX)
X	   	error("Remote System Not Responding on Completion", TRUE);
X
X    	close(fd);
X
X    	logit("Send Complete\n");
X	prtime(sentsect, time((time_t *) 0) - start);
X	}
!Funky!Stuff!
exit

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list