[comp.sources.amiga] v89i180: vt100 - terminal emulator v2.9, Part03/09

page%swap@Sun.COM (Bob Page) (10/20/89)

Submitted-by: acs@pccuts.pcc.amdahl.com (Tony Sumrall)
Posting-number: Volume 89, Issue 180
Archive-name: comm/vt100r29.3

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	Zmodem/rbsb.c
#	Zmodem/zm.c
#	Zmodem/sz.c
# This is archive 3 of a 9-part kit.
# This archive created: Thu Oct 19 22:30:29 1989
if `test ! -d Zmodem`
then
  mkdir Zmodem
  echo "mkdir Zmodem"
fi
echo "extracting Zmodem/rbsb.c"
sed 's/^X//' << \SHAR_EOF > Zmodem/rbsb.c
X/*
X *
X * -rev 04-16-87
X *  This file contains Unix specific code for setting terminal modes,
X *  very little is specific to ZMODEM or YMODEM per se (that code is in
X *  sz.c and rz.c).  The CRC-16 routines used by XMODEM, YMODEM, and ZMODEM
X *  are also in this file, a fast table driven macro version
X *
X *   This file is #included so the main file can set parameters such as HOWMANY.
X *   See the main files (rz.c/sz.c) for compile instructions.
X */
X#ifdef AMIGA
X#define OS "the Amiga"
Xstruct IOExtSer *SetSer();
XULONG Len,Stop,ParFlags;
Xchar ParityCH; /* parity character N=none,E=even,O=odd */
X
X/*
X * if op is 0 then clean up and prepare for exit
X * if op is 1 then init serial port, timers etc.
X * bomb for the other modes
X */
Xmode(op)
Xint op;
X{
X  struct IOExtSer *Ser;
X
X  switch(op)
X   {
X	case 1:if( SetTimer()!=0 ) return ERROR;
X	       else {
X		    InitParams();
X		    if( (Ser=SetSer(InitSer?Baudrate:-1,Len,Stop,SERF_SHARED|SERF_XDISABLED|ParFlags))==NULL )
X		       return ERROR;
X	       }
X	       UpDateParms(Ser);
X	       fprintf(stderr,"Transferring at %d baud, %d%c%d\n",Baudrate,Len,ParityCH,Stop);
X#ifndef RZ     /* sz needs bigger buffer for higher speeds */
X	       if (Baudrate > 300)
X			BufferSize = 256;
X	       if (Baudrate > 1200)
X			BufferSize = 512;
X	       if (Baudrate > 2400)
X			BufferSize = KSIZE;
X	       if (Rxbuflen && BufferSize>Rxbuflen)
X			BufferSize = Rxbuflen;
X	       if (blkopt && BufferSize > blkopt)
X			BufferSize = blkopt;
X	       Next=OutBuf=(UBYTE *)malloc(BufferSize);
X#endif
X		return OK;
X
X	case 0:
X		   CloseSer();
X		   CloseTimer();
X#ifndef RZ
X		   if(OutBuf) free(OutBuf);
X#endif
X		   return OK;
X
X	default: /* bomb for other modes */
X		 return ERROR;
X    }
X
X}
X
XInitParams()
X{
X FILE *fparm;
X
X  if( (fparm=fopen("zmodem.init","r"))==NULL &&
X      (fparm=fopen("S:zmodem.init","r"))==NULL)
X  {
X    /* default to preferences */
X    InitSer = FALSE;
X   }
X  else
X      {
X       gmt_diff=100;
X       fscanf(fparm,"%d %d%c%d %d",&Baudrate,&Len,&ParityCH,&Stop,&gmt_diff);
X       if(gmt_diff!=100) gmt_diff_set=TRUE;
X       fclose(fparm);
X       switch(ParityCH)
X       {
X	case 'E':
X	case 'e': ParFlags = SERF_PARTY_ON;break;
X
X	case 'o':
X	case 'O': ParFlags = SERF_PARTY_ON|SERF_PARTY_ODD;break;
X
X	default : ParFlags = NULL;
X       }
X }
X}
X
XUpDateParms(SS)
Xstruct IOExtSer *SS;
X{
X  if( !InitSer)
X  {
X    Baudrate = SS->io_Baud;
X    Len      = SS->io_ReadLen;
X    Stop     = SS->io_StopBits;
X    if( SS->io_SerFlags & SERF_PARTY_ON)
X    {
X	if( SS->io_SerFlags & SERF_PARTY_ODD)
X	    ParityCH = 'O';
X	else
X	    ParityCH= 'E';
X     }
X    else
X	ParityCH = 'N';
X   }
X  if( Len<8 || ParityCH!='N')
X   {
X     /* set 7 bit text mode */
X     Wcsmask = 0177;
X#ifdef RZ
X     Rxascii=TRUE;
X#else
X     Lzconv = 2;   /* This 2 is really ZCNL, but the way the includes are */
X     Ascii = TRUE; /* set up I had to hack it this way */
X#endif
X    }
X}
X
Xsleep(n)
Xint n;
X{
X
X
X   if(n>0) Delay (50*n);
X   return (0);
X}
X#else /* UNIX versions */
X#ifdef V7
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sgtty.h>
X#define OS "V7/BSD"
X#endif
X
X#ifndef OS
X#ifndef USG
X#define USG
X#endif
X#endif
X
X#ifdef USG
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <termio.h>
X#include <sys/ioctl.h>
X#define OS "SYS III/V"
X#endif
X
X#if HOWMANY  > 255
XHowmany must be 255 or less
X#endif
X
Xstruct {
X	unsigned baudr;
X	int speedcode;
X} speeds[] = {
X	110,	B110,
X	300,	B300,
X	600,	B600,
X	1200,	B1200,
X	2400,	B2400,
X	4800,	B4800,
X	9600,	B9600,
X	19200,	EXTA,
X	9600,	EXTB,
X	0,
X};
X
Xint Twostop;		/* Use two stop bits */
X
Xstatic unsigned
Xgetspeed(code)
X{
X	register n;
X
X	for (n=0; speeds[n].baudr; ++n)
X		if (speeds[n].speedcode == code)
X			return speeds[n].baudr;
X	return 0;
X}
X
X
X
X#ifdef ICANON
Xstruct termio oldtty, tty;
X#else
Xstruct sgttyb oldtty, tty;
Xstruct tchars oldtch, tch;
X#endif
X
Xint iofd = 0;		/* File descriptor for ioctls & reads */
X
X/*
X * mode(n)
X *  3: save old tty stat, set raw mode with flow control
X *  2: set a cbreak, XON/XOFF control mode if using Pro-YAM's -g option
X *  1: save old tty stat, set raw mode
X *  0: restore original tty mode
X */
Xmode(n)
X{
X	static did0 = FALSE;
X
X	vfile("mode:%d", n);
X	switch(n) {
X#ifdef USG
X	case 2: /* Cbreak mode used by sb when -g detected */
X		if(!did0)
X			(void) ioctl(iofd, TCGETA, &oldtty);
X		tty = oldtty;
X
X		tty.c_iflag = BRKINT|IXON;
X
X		tty.c_oflag = 0;	/* Transparent output */
X
X		tty.c_cflag &= ~PARENB; /* Disable parity */
X		tty.c_cflag |= CS8;	/* Set character size = 8 */
X		if (Twostop)
X			tty.c_cflag |= CSTOPB;	/* Set two stop bits */
X
X		tty.c_lflag =
X#ifdef XCLUDE
X		  XCLUDE |
X#endif
X		  Zmodem ? 0 : ISIG;
X
X		tty.c_cc[VINTR] = 030;		/* Interrupt char */
X		tty.c_cc[VMIN] = 1;
X
X		(void) ioctl(iofd, TCSETAW, &tty);
X		did0 = TRUE;
X		return OK;
X	case 1:
X	case 3:
X		if(!did0)
X			(void) ioctl(iofd, TCGETA, &oldtty);
X		tty = oldtty;
X
X		tty.c_iflag = n==3 ? (IGNBRK|IXOFF) : IGNBRK;
X
X		 /* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */
X		tty.c_lflag &= ~(ECHO | ICANON | ISIG);
X#ifdef XCLUDE
X		tty.c_lflag |= XCLUDE;
X#endif
X
X		tty.c_oflag = 0;	/* Transparent output */
X
X		tty.c_cflag &= ~PARENB; /* Same baud rate, disable parity */
X		tty.c_cflag |= CS8;	/* Set character size = 8 */
X		if (Twostop)
X			tty.c_cflag |= CSTOPB;	/* Set two stop bits */
X#ifdef NFGVMIN
X		tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */
X#else
X		tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */
X#endif
X		tty.c_cc[VTIME] = 1;	/* or in this many tenths of seconds */
X		(void) ioctl(iofd, TCSETAW, &tty);
X		did0 = TRUE;
X		Baudrate = getspeed(tty.c_cflag & CBAUD);
X		return OK;
X#endif
X#ifdef V7
X	case 2: /*  This doesn't work ... */
X		printf("No mode(2) in V7/BSD!"); bibi(99);
X		if(!did0) {
X			ioctl(iofd, TIOCEXCL, 0);
X			ioctl(iofd, TIOCGETP, &oldtty);
X			ioctl(iofd, TIOCGETC, &oldtch);
X		}
X		tty = oldtty;
X		tch = oldtch;
X		tch.t_intrc = Zmodem ? 03:030;	/* Interrupt char */
X		tty.sg_flags |= (ODDP|EVENP|CBREAK);
X		tty.sg_flags &= ~(ALLDELAY|CRMOD|ECHO|LCASE);
X		ioctl(iofd, TIOCSETP, &tty);
X		ioctl(iofd, TIOCSETC, &tch);
X		did0 = TRUE;
X		return OK;
X	case 1:
X	case 3:
X		if(!did0) {
X			ioctl(iofd, TIOCEXCL, 0);
X			ioctl(iofd, TIOCGETP, &oldtty);
X			ioctl(iofd, TIOCGETC, &oldtch);
X		}
X		tty = oldtty;
X		tty.sg_flags |= RAW;
X		tty.sg_flags &= ~ECHO;
X		ioctl(iofd, TIOCSETP, &tty);
X		did0 = TRUE;
X		Baudrate = getspeed(tty.sg_ospeed);
X		return OK;
X#endif
X	case 0:
X		if(!did0)
X			return ERROR;
X#ifdef USG
X		(void) ioctl(iofd, TCSBRK, 1);  /* Wait for output to drain */
X		(void) ioctl(iofd, TCFLSH, 1);  /* Flush input queue */
X		(void) ioctl(iofd, TCSETAW, &oldtty);   /* Restore original modes */
X		(void) ioctl(iofd, TCXONC,1);   /* Restart output */
X#endif
X#ifdef V7
X		ioctl(iofd, TIOCSETP, &oldtty);
X		ioctl(iofd, TIOCSETC, &oldtch);
X		ioctl(iofd, TIOCNXCL, 0);
X#endif
X		return OK;
X	default:
X		return ERROR;
X	}
X}
X#endif
X
Xsendbrk()
X{
X#ifdef AMIGA
X    SendBreak();
X#else
X#ifdef V7
X#ifdef TIOCSBRK
X#define CANBREAK
X	sleep(1);
X	ioctl(iofd, TIOCSBRK, 0);
X	sleep(1);
X	ioctl(iofd, TIOCCBRK, 0);
X#endif
X#endif
X#ifdef USG
X#define CANBREAK
X	ioctl(iofd, TCSBRK, 0);
X#endif
X#endif /* AMIGA */
X}
X
X#ifdef AMIGA
Xrdchk()
X{
X    if (SerOpen) {
X	if (Lleft>0) return Lleft;
X	else return CharsWaiting();
X    }
X}
X#else
X#ifdef FIONREAD
X#define READCHECK
X/*
X *  Return non 0 iff something to read from io descriptor f
X */
Xrdchk(f)
X{
X	static long lf;
X
X	ioctl(f, FIONREAD, &lf);
X	return ((int) lf);
X}
X#endif
X#ifdef SVR2
X#define READCHECK
X#include <fcntl.h>
X
Xchar checked = '\0' ;
X/*
X * Nonblocking I/O is a bit different in System V, Release 2
X */
Xrdchk(f)
X{
X	int lf, savestat = fcntl(f, F_GETFL) ;
X
X	fcntl(f, F_SETFL, savestat | O_NDELAY) ;
X	lf = read(f, &checked, 1) ;
X	fcntl(f, F_SETFL, savestat) ;
X	return(lf) ;
X}
X#endif
X#endif
X
X/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
Xstatic unsigned short crctab[256] = {
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/*
X * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
X *  NOTE: First srgument must be in range 0 to 255.
X *	  Second argument is referenced twice.
X *
X * Programmers may incorporate any or all code into their programs,
X * giving proper credit within the source. Publication of the
X * source routines is permitted so long as proper credit is given
X * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
X * Omen Technology.
X */
X
X#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
X
X/*
X * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
X * code or tables extracted from it, as desired without restriction.
X */
X
X/* First, the polynomial itself and its table of feedback terms.  The  */
X/* polynomial is						       */
X/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
X/* Note that we take it "backwards" and put the highest-order term in  */
X/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
X/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
X/* the MSB being 1.						       */
X
X/* Note that the usual hardware shift register implementation, which   */
X/* is what we're using (we're merely optimizing it by doing eight-bit  */
X/* chunks at a time) shifts bits into the lowest-order term.  In our   */
X/* implementation, that means shifting towards the right.  Why do we   */
X/* do it this way?  Because the calculated CRC must be transmitted in  */
X/* order from highest-order term to lowest-order term.	UARTs transmit */
X/* characters in order from LSB to MSB.  By storing the CRC this way,  */
X/* we hand it to the UART in the order low-byte to high-byte; the UART */
X/* sends each low-bit to hight-bit; and the result is transmission bit */
X/* by bit from highest- to lowest-order term without requiring any bit */
X/* shuffling on our part.  Reception works similarly.		       */
X
X/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
X/*								       */
X/*     The table can be generated at runtime if desired; code to do so */
X/*     is shown later.	It might not be obvious, but the feedback      */
X/*     terms simply represent the results of eight shift/xor opera-    */
X/*     tions for all combinations of data and CRC register values.     */
X/*								       */
X/*     The values must be right-shifted by eight bits by the "updcrc"  */
X/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
X/*     hardware you could probably optimize the shift in assembler by  */
X/*     using byte-swap instructions.				       */
X
Xstatic long cr3tab[] = { /* CRC polynomial 0xedb88320 */
X0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
X0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
X0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
X0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
X0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
X0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
X0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
X0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
X0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
X0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
X0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
X0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
X0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
X0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
X0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
X0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
X0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
X0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
X0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
X0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
X0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
X0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
X0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
X0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
X0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
X0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
X0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
X0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
X0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
X0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
X#ifdef NFGM
Xlong
XUPDC32(b, c)
Xlong c;
X{
X	return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF));
X}
X
X#else
X
X#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
X#endif
X
X/* End of rbsb.c */
SHAR_EOF
echo "extracting Zmodem/zm.c"
sed 's/^X//' << \SHAR_EOF > Zmodem/zm.c
X/*
X *   Z M . C
X *    ZMODEM protocol primitives
X *    07-28-87	Chuck Forsberg Omen Technology Inc
X *
X * Entry point Functions:
X *	zsbhdr(type, hdr) send binary header
X *	zshhdr(type, hdr) send hex header
X *	zgethdr(hdr, eflag) receive header - binary or hex
X *	zsdata(buf, len, frameend) send data
X *	zrdata(buf, len) receive data
X *	stohdr(pos) store position data in Txhdr
X *	long rclhdr(hdr) recover position offset from header
X */
X
X#ifndef CANFDX
X#include "zmodem.h"
Xint Rxtimeout = 100;		/* Tenths of seconds to wait for something */
X#endif
X
X
X#ifndef UNSL
X#define UNSL
X#endif
X
X
X/* Globals used by ZMODEM functions */
Xint Rxframeind; 	/* ZBIN ZBIN32, or ZHEX type of frame received */
Xint Rxtype;		/* Type of header received */
Xint Rxcount;		/* Count of data bytes received */
Xchar Rxhdr[4];		/* Received header */
Xchar Txhdr[4];		/* Transmitted header */
Xlong Rxpos;		/* Received file position */
Xlong Txpos;		/* Transmitted file position */
Xint Txfcs32;		/* TURE means send binary frames with 32 bit FCS */
Xint Crc32t;		/* Display flag indicating 32 bit CRC being sent */
Xint Crc32;		/* Display flag indicating 32 bit CRC being received */
Xint Znulls;		/* Number of nulls to send at beginning of ZDATA hdr */
Xchar Attn[ZATTNLEN+1];	/* Attention string rx sends to tx on err */
X
X
Xstatic char *frametypes[] = {
X	"Carrier Lost",         /* -3 */
X	"TIMEOUT",              /* -2 */
X	"ERROR",                /* -1 */
X#define FTOFFSET 3
X	"ZRQINIT",
X	"ZRINIT",
X	"ZSINIT",
X	"ZACK",
X	"ZFILE",
X	"ZSKIP",
X	"ZNAK",
X	"ZABORT",
X	"ZFIN",
X	"ZRPOS",
X	"ZDATA",
X	"ZEOF",
X	"ZFERR",
X	"ZCRC",
X	"ZCHALLENGE",
X	"ZCOMPL",
X	"ZCAN",
X	"ZFREECNT",
X	"ZCOMMAND",
X	"ZSTDERR",
X	"xxxxx"
X#define FRTYPES 22	/* Total number of frame types in this array */
X			/*  not including psuedo negative entries */
X};
X
X/* Send ZMODEM binary header hdr of type type */
Xzsbhdr(type, hdr)
Xregister char *hdr;
X{
X	register n;
X	register unsigned short crc;
X
X	vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
X	if (type == ZDATA)
X		for (n = Znulls; --n >=0; )
X			zsendline(0);
X
X	xsendline(ZPAD); xsendline(ZDLE);
X
X	if (Crc32t=Txfcs32)
X		zsbh32(hdr, type);
X	else {
X		xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
X
X		for (n=4; --n >= 0; ++hdr) {
X			zsendline(*hdr);
X			crc = updcrc((0377& *hdr), crc);
X		}
X		crc = updcrc(0,updcrc(0,crc));
X		zsendline(crc>>8);
X		zsendline(crc);
X	}
X#ifndef AMIGA
X	if (type != ZDATA)
X		flushmo();
X#else
X	flushmo();
X#endif
X}
X
X
X/* Send ZMODEM binary header hdr of type type */
Xzsbh32(hdr, type)
Xregister char *hdr;
X{
X	register n;
X	register UNSL long crc;
X
X	xsendline(ZBIN32);  zsendline(type);
X	crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
X
X	for (n=4; --n >= 0; ++hdr) {
X		crc = UPDC32((0377 & *hdr), crc);
X		zsendline(*hdr);
X	}
X	crc = ~crc;
X	for (n=4; --n >= 0;) {
X		zsendline((int)crc);
X		crc >>= 8;
X	}
X#ifdef AMIGA
X	flushmo();
X#endif
X}
X
X/* Send ZMODEM HEX header hdr of type type */
Xzshhdr(type, hdr)
Xregister char *hdr;
X{
X	register n;
X	register unsigned short crc;
X
X	vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
X	sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
X	zputhex(type);
X	Crc32t = 0;
X
X	crc = updcrc(type, 0);
X	for (n=4; --n >= 0; ++hdr) {
X		zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
X	}
X	crc = updcrc(0,updcrc(0,crc));
X	zputhex(crc>>8); zputhex(crc);
X
X	/* Make it printable on remote machine */
X	sendline(015); sendline(012);
X	/*
X	 * Uncork the remote in case a fake XOFF has stopped data flow
X	 */
X	if (type != ZFIN && type != ZACK)
X		sendline(021);
X	flushmo();
X}
X
X/*
X * Send binary array buf of length length, with ending ZDLE sequence frameend
X */
Xzsdata(buf, length, frameend)
Xregister char *buf;
X{
X	register unsigned short crc;
X
X	vfile("zsdata: length=%d end=%x", length, frameend);
X	if (Crc32t)
X		zsda32(buf, length, frameend);
X	else {
X		crc = 0;
X		for (;--length >= 0; ++buf) {
X			zsendline(*buf); crc = updcrc((0377 & *buf), crc);
X		}
X		xsendline(ZDLE); xsendline(frameend);
X		crc = updcrc(frameend, crc);
X
X		crc = updcrc(0,updcrc(0,crc));
X		zsendline(crc>>8); zsendline(crc);
X	}
X	if (frameend == ZCRCW) {
X		xsendline(XON);  flushmo();
X	}
X#ifdef AMIGA
X	else flushmo();
X#endif
X}
X
Xzsda32(buf, length, frameend)
Xregister char *buf;
X{
X	register UNSL long crc;
X
X	crc = 0xFFFFFFFFL;
X	for (;--length >= 0;++buf) {
X		crc = UPDC32((0377 & *buf), crc);
X		zsendline(*buf);
X	}
X	xsendline(ZDLE); xsendline(frameend);
X	crc = UPDC32(frameend, crc);
X
X	crc = ~crc;
X	for (length=4; --length >= 0;) {
X		zsendline((int)crc);  crc >>= 8;
X	}
X}
X
X/*
X * Receive array buf of max length with ending ZDLE sequence
X *  and CRC.  Returns the ending character or error code.
X *  NB: On errors may store length+1 bytes!
X */
Xzrdata(buf, length)
Xregister char *buf;
X{
X	register c;
X	register unsigned short crc;
X	register char *end;
X	register d;
X
X	if (Rxframeind == ZBIN32)
X		return zrdat32(buf, length);
X
X	crc = Rxcount = 0;  end = buf + length;
X	while (buf <= end) {
X		if ((c = zdlread()) & ~0377) {
Xcrcfoo:
X			switch (c) {
X			case GOTCRCE:
X			case GOTCRCG:
X			case GOTCRCQ:
X			case GOTCRCW:
X				crc = updcrc((d=c)&0377, crc);
X				if ((c = zdlread()) & ~0377)
X					goto crcfoo;
X				crc = updcrc(c, crc);
X				if ((c = zdlread()) & ~0377)
X					goto crcfoo;
X				crc = updcrc(c, crc);
X				if (crc & 0xFFFF) {
X					zperr("Bad data CRC");
X					return ERROR;
X				}
X				Rxcount = length - (end - buf);
X				vfile("zrdata: cnt = %d ret = %x", Rxcount, d);
X				return d;
X			case GOTCAN:
X				zperr("Sender Canceled");
X				return ZCAN;
X			case TIMEOUT:
X				zperr("TIMEOUT");
X				return c;
X			default:
X				zperr("Bad data subpacket");
X				return c;
X			}
X		}
X		*buf++ = c;
X		crc = updcrc(c, crc);
X	}
X	zperr("Data subpacket too long");
X	return ERROR;
X}
X
Xzrdat32(buf, length)
Xregister char *buf;
X{
X	register c;
X	register UNSL long crc;
X	register char *end;
X	register d;
X
X	crc = 0xFFFFFFFFL;  Rxcount = 0;  end = buf + length;
X	while (buf <= end) {
X		if ((c = zdlread()) & ~0377) {
Xcrcfoo:
X			switch (c) {
X			case GOTCRCE:
X			case GOTCRCG:
X			case GOTCRCQ:
X			case GOTCRCW:
X				d = c;	c &= 0377;
X				crc = UPDC32(c, crc);
X				if ((c = zdlread()) & ~0377)
X					goto crcfoo;
X				crc = UPDC32(c, crc);
X				if ((c = zdlread()) & ~0377)
X					goto crcfoo;
X				crc = UPDC32(c, crc);
X				if ((c = zdlread()) & ~0377)
X					goto crcfoo;
X				crc = UPDC32(c, crc);
X				if ((c = zdlread()) & ~0377)
X					goto crcfoo;
X				crc = UPDC32(c, crc);
X				if (crc != 0xDEBB20E3) {
X					zperr("Bad data CRC");
X					return ERROR;
X				}
X				Rxcount = length - (end - buf);
X				vfile("zrdat32: cnt = %d ret = %x", Rxcount, d);
X				return d;
X			case GOTCAN:
X				zperr("Sender Canceled");
X				return ZCAN;
X			case TIMEOUT:
X				zperr("TIMEOUT");
X				return c;
X			default:
X				zperr("Bad data subpacket");
X				return c;
X			}
X		}
X		*buf++ = c;
X		crc = UPDC32(c, crc);
X	}
X	zperr("Data subpacket too long");
X	return ERROR;
X}
X
X
X/*
X * Read a ZMODEM header to hdr, either binary or hex.
X *  eflag controls local display of non zmodem characters:
X *	0:  no display
X *	1:  display printing characters only
X *	2:  display all non ZMODEM characters
X *  On success, set Zmodem to 1, set Rxpos and return type of header.
X *   Otherwise return negative on error.
X *   Return ERROR instantly if ZCRCW sequence, for fast error recovery.
X */
Xzgethdr(hdr, eflag)
Xchar *hdr;
X{
X	register c, n, cancount;
X
X	n = Zrwindow + Baudrate;	/* Max bytes before start of frame */
X	Rxframeind = Rxtype = 0;
X
Xstartover:
X	cancount = 5;
Xagain:
X	/* Return immediate ERROR if ZCRCW sequence seen */
X	switch (c = readline(Rxtimeout)) {
X	case RCDO:
X	case TIMEOUT:
X		goto fifi;
X	case CAN:
Xgotcan:
X		if (--cancount <= 0) {
X			c = ZCAN; goto fifi;
X		}
X		switch (c = readline(1)) {
X		case TIMEOUT:
X			goto again;
X		case ZCRCW:
X			c = ERROR;
X		/* **** FALL THRU TO **** */
X		case RCDO:
X			goto fifi;
X		default:
X			break;
X		case CAN:
X			if (--cancount <= 0) {
X				c = ZCAN; goto fifi;
X			}
X			goto again;
X		}
X	/* **** FALL THRU TO **** */
X	default:
Xagn2:
X		if ( --n == 0) {
X			zperr("Garbage count exceeded");
X			return(ERROR);
X		}
X		if (eflag && ((c &= 0177) & 0140))
X			bttyout(c);
X		else if (eflag > 1)
X			bttyout(c);
X		goto startover;
X	case ZPAD|0200: 	/* This is what we want. */
X	case ZPAD:		/* This is what we want. */
X		break;
X	}
X	cancount = 5;
Xsplat:
X	switch (c = noxrd7()) {
X	case ZPAD:
X		goto splat;
X	case RCDO:
X	case TIMEOUT:
X		goto fifi;
X	default:
X		goto agn2;
X	case ZDLE:		/* This is what we want. */
X		break;
X	}
X
X	switch (c = noxrd7()) {
X	case RCDO:
X	case TIMEOUT:
X		goto fifi;
X	case ZBIN:
X		Rxframeind = ZBIN;  Crc32 = FALSE;
X		c =  zrbhdr(hdr);
X		break;
X	case ZBIN32:
X		Crc32 = Rxframeind = ZBIN32;
X		c =  zrbhdr32(hdr);
X		break;
X	case ZHEX:
X		Rxframeind = ZHEX;  Crc32 = FALSE;
X		c =  zrhhdr(hdr);
X		break;
X	case CAN:
X		goto gotcan;
X	default:
X		goto agn2;
X	}
X	Rxpos = hdr[ZP3] & 0377;
X	Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
X	Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
X	Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
Xfifi:
X	switch (c) {
X	case GOTCAN:
X		c = ZCAN;
X	/* **** FALL THRU TO **** */
X	case ZNAK:
X	case ZCAN:
X	case ERROR:
X	case TIMEOUT:
X	case RCDO:
X		zperr("Got %s", frametypes[c+FTOFFSET]);
X	/* **** FALL THRU TO **** */
X	default:
X		if (c >= -3 && c <= FRTYPES)
X			vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
X		else
X			vfile("zgethdr: %d %lx", c, Rxpos);
X	}
X	return c;
X}
X
X/* Receive a binary style header (type and position) */
Xzrbhdr(hdr)
Xregister char *hdr;
X{
X	register c, n;
X	register unsigned short crc;
X
X	if ((c = zdlread()) & ~0377)
X		return c;
X	Rxtype = c;
X	crc = updcrc(c, 0);
X
X	for (n=4; --n >= 0; ++hdr) {
X		if ((c = zdlread()) & ~0377)
X			return c;
X		crc = updcrc(c, crc);
X		*hdr = c;
X	}
X	if ((c = zdlread()) & ~0377)
X		return c;
X	crc = updcrc(c, crc);
X	if ((c = zdlread()) & ~0377)
X		return c;
X	crc = updcrc(c, crc);
X	if (crc & 0xFFFF) {
X		zperr("Bad Header CRC"); return ERROR;
X	}
X	Zmodem = 1;
X	return Rxtype;
X}
X
X/* Receive a binary style header (type and position) with 32 bit FCS */
Xzrbhdr32(hdr)
Xregister char *hdr;
X{
X	register c, n;
X	register UNSL long crc;
X
X	if ((c = zdlread()) & ~0377)
X		return c;
X	Rxtype = c;
X	crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
X#ifdef DEBUGZ
X	vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
X#endif
X
X	for (n=4; --n >= 0; ++hdr) {
X		if ((c = zdlread()) & ~0377)
X			return c;
X		crc = UPDC32(c, crc);
X		*hdr = c;
X#ifdef DEBUGZ
X		vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
X#endif
X	}
X	for (n=4; --n >= 0;) {
X		if ((c = zdlread()) & ~0377)
X			return c;
X		crc = UPDC32(c, crc);
X#ifdef DEBUGZ
X		vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
X#endif
X	}
X	if (crc != 0xDEBB20E3) {
X		zperr("Bad Header CRC"); return ERROR;
X	}
X	Zmodem = 1;
X	return Rxtype;
X}
X
X
X/* Receive a hex style header (type and position) */
Xzrhhdr(hdr)
Xchar *hdr;
X{
X	register c;
X	register unsigned short crc;
X	register n;
X
X	if ((c = zgethex()) < 0)
X		return c;
X	Rxtype = c;
X	crc = updcrc(c, 0);
X
X	for (n=4; --n >= 0; ++hdr) {
X		if ((c = zgethex()) < 0)
X			return c;
X		crc = updcrc(c, crc);
X		*hdr = c;
X	}
X	if ((c = zgethex()) < 0)
X		return c;
X	crc = updcrc(c, crc);
X	if ((c = zgethex()) < 0)
X		return c;
X	crc = updcrc(c, crc);
X	if (crc & 0xFFFF) {
X		zperr("Bad Header CRC"); return ERROR;
X	}
X	if (readline(1) == '\r')        /* Throw away possible cr/lf */
X		readline(1);
X	Zmodem = 1; return Rxtype;
X}
X
X/* Send a byte as two hex digits */
Xzputhex(c)
Xregister c;
X{
X	static char	digits[]	= "0123456789abcdef";
X
X	if (Verbose>8)
X		vfile("zputhex: %02X", c);
X	sendline(digits[(c&0xF0)>>4]);
X	sendline(digits[(c)&0xF]);
X}
X
X/*
X * Send character c with ZMODEM escape sequence encoding.
X *  Escape XON, XOFF. Escape CR following @ (Telenet net escape)
X */
Xzsendline(c)
Xregister c;
X{
X	static lastsent;
X
X	switch (c &= 0377) {
X	case ZDLE:
X		xsendline(ZDLE);
X		xsendline (lastsent = (c ^= 0100));
X		break;
X	case 015:
X	case 0215:
X		if (!Zctlesc && (lastsent & 0177) != '@')
X			goto sendit;
X	/* **** FALL THRU TO **** */
X	case 020:
X	case 021:
X	case 023:
X	case 0220:
X	case 0221:
X	case 0223:
X		xsendline(ZDLE);
X		c ^= 0100;
Xsendit:
X		xsendline(lastsent = c);
X		break;
X	default:
X		if (Zctlesc && ! (c & 0140)) {
X			xsendline(ZDLE);
X			c ^= 0100;
X		}
X		xsendline(lastsent = c);
X	}
X}
X
X/* Decode two lower case hex digits into an 8 bit byte value */
Xzgethex()
X{
X	register c;
X
X	c = zgeth1();
X	if (Verbose>8)
X		vfile("zgethex: %02X", c);
X	return c;
X}
Xzgeth1()
X{
X	register c, n;
X
X	if ((c = noxrd7()) < 0)
X		return c;
X	n = c - '0';
X	if (n > 9)
X		n -= ('a' - ':');
X	if (n & ~0xF)
X		return ERROR;
X	if ((c = noxrd7()) < 0)
X		return c;
X	c -= '0';
X	if (c > 9)
X		c -= ('a' - ':');
X	if (c & ~0xF)
X		return ERROR;
X	c += (n<<4);
X	return c;
X}
X
X/*
X * Read a byte, checking for ZMODEM escape encoding
X *  including CAN*5 which represents a quick abort
X */
Xzdlread()
X{
X	register c;
X
Xagain:
X	switch (c = readline(Rxtimeout)) {
X	case ZDLE:
X		break;
X	case 023:
X	case 0223:
X	case 021:
X	case 0221:
X		goto again;
X	default:
X		if (Zctlesc && !(c & 0140)) {
X			goto again;
X		}
X		return c;
X	}
Xagain2:
X	if ((c = readline(Rxtimeout)) < 0)
X		return c;
X	if (c == CAN && (c = readline(Rxtimeout)) < 0)
X		return c;
X	if (c == CAN && (c = readline(Rxtimeout)) < 0)
X		return c;
X	if (c == CAN && (c = readline(Rxtimeout)) < 0)
X		return c;
X	switch (c) {
X	case CAN:
X		return GOTCAN;
X	case ZCRCE:
X	case ZCRCG:
X	case ZCRCQ:
X	case ZCRCW:
X		return (c | GOTOR);
X	case ZRUB0:
X		return 0177;
X	case ZRUB1:
X		return 0377;
X	case 023:
X	case 0223:
X	case 021:
X	case 0221:
X		goto again2;
X	default:
X		if (Zctlesc && ! (c & 0140)) {
X			goto again2;
X		}
X		if ((c & 0140) ==  0100)
X			return (c ^ 0100);
X		break;
X	}
X	zperr("Bad escape sequence %x", c);
X	return ERROR;
X}
X
X/*
X * Read a character from the modem line with timeout.
X *  Eat parity, XON and XOFF characters.
X */
Xnoxrd7()
X{
X	register c;
X
X	for (;;) {
X		if ((c = readline(Rxtimeout)) < 0)
X			return c;
X		switch (c &= 0177) {
X		case XON:
X		case XOFF:
X			continue;
X		default:
X			if (Zctlesc && !(c & 0140))
X				continue;
X		case '\r':
X		case '\n':
X		case ZDLE:
X			return c;
X		}
X	}
X}
X
X/* Store long integer pos in Txhdr */
Xstohdr(pos)
Xlong pos;
X{
X	Txhdr[ZP0] = pos;
X	Txhdr[ZP1] = pos>>8;
X	Txhdr[ZP2] = pos>>16;
X	Txhdr[ZP3] = pos>>24;
X}
X
X/* Recover a long integer from a header */
Xlong
Xrclhdr(hdr)
Xregister char *hdr;
X{
X	register long l;
X
X	l = (hdr[ZP3] & 0377);
X	l = (l << 8) | (hdr[ZP2] & 0377);
X	l = (l << 8) | (hdr[ZP1] & 0377);
X	l = (l << 8) | (hdr[ZP0] & 0377);
X	return l;
X}
X
X/* End of zm.c */
SHAR_EOF
echo "extracting Zmodem/sz.c"
sed 's/^X//' << \SHAR_EOF > Zmodem/sz.c
X#define VERSION "sz 1.36 08-31-87"
X#define PUBDIR "/usr/spool/uucppublic"
X
X/*% cc -M0 -Ox -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz
X *
X * sz.c By Chuck Forsberg
X *
X * Amiga version by Frank Harper using Aztec C 3.4b
X *
X *	cc +L sz.c;cc +L SerIO.c;cc +L term.c;ln sz.o SerIO.o term.o -lc32
X *	or just use the makefile
X *
X * See Amiga.doc for more details on Amiga version
X *
X *	cc -O sz.c -o sz		USG (SYS III/V) Unix
X *	cc -O -DSVR2 sz.c -o sz 	Sys V Release 2 with non-blocking input
X *					Define to allow reverse channel checking
X *	cc -O -DV7  sz.c -o sz		Unix Version 7, 2.8 - 4.3 BSD
X *
X *	cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz	Xenix
X *
X *	ln sz sb			**** All versions ****
X *	ln sz sx			**** All versions ****
X *
X *
X *  ******* Some systems (Venix, Coherent, Regulus) do not *******
X *  ******* support tty raw mode read(2) identically to    *******
X *  ******* Unix. ONEREAD must be defined to force one	   *******
X *  ******* character reads for these systems.		   *******
X *
X * A program for Unix to send files and commands to computers running
X *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
X *
X *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
X *
X *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
X *
X * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
X * in accordance with the 7-31-87 ZMODEM Protocol Description
X */
X
X
Xchar *substr(), *getenv();
X
X#define PATHLEN 256
X#define OK 0
X#define ERROR (-1)
X
X#ifdef AMIGA
X#include <stdio.h>
X#include <ctype.h>
X#include <stat.h>
X#include <devices/timer.h>
X#include <devices/serial.h>
X#include <libraries/dos.h>
X#include "intuition/intuition.h"
X
X#define LOGFILE "szlog"
X#define READCHECK
X
Xvoid *malloc();
Xvoid *OpenLibrary();
Xstruct Window *OpenWindow();
X
Xstruct IntuitionBase *IntuitionBase;
Xstruct NewWindow nw = {
X   0, 0,	     /* start position			*/
X   640, 120,	     /* width, height			*/
X   -1, -1,	     /* detail pen, block pen		*/
X   CLOSEWINDOW, 	      /* IDCMP flags			 */
X   ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | WINDOWCLOSE
X   | NOCAREREFRESH, /* window flags		       */
X   NULL,	     /* pointer to first user gadget	*/
X   NULL,	     /* pointer to user checkmark	*/
X   (UBYTE *)"Sz",             /* window title                    */
X   NULL,	     /* pointer to screen    (later)    */
X   NULL,	     /* pointer to superbitmap		*/
X   50,40,-1,-1,  /* sizing limits min and max	    */
X   WBENCHSCREEN      /* type of screen in which to open */
X   };
X
Xint Lleft;
Xint InitSer = FALSE;
Xint gmt_diff_set=FALSE; /* Has GMT offset been set? */
Xint gmt_diff;		/* Local time offset from GMT time */
Xint SendProtect=TRUE;	/* send file protection bits? */
Xint Term=FALSE; 	/* Use Terminal mode ? */
Xint WaitC=TRUE; 	/* Wait for confirmation before closing window?*/
Xstruct IOStdReq *ConWriteReq, *ConReadReq;
Xstruct Window *Win;
Xstruct MsgPort	*ConReadPort,*ConWritePort;
Xint WinOutPut;
Xint FullDuplex=TRUE;
XULONG  InSerSigMask, OutSerSigMask;
XUBYTE  SerOpen;
XULONG  IOTimeSigMask;
Xstruct IOExtSer *InSer, *OutSer;
Xstruct MsgPort	*InSerPort, *OutSerPort;
Xstruct timerequest *IOTime;
Xstruct MsgPort *TimerPort;
X#else
X#define LOGFILE "/tmp/szlog"
X
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <ctype.h>
X
X#define FALSE 0
X#define TRUE 1
X#endif /* AMIGA */
X
X#define HOWMANY 2
Xint Zmodem=0;		/* ZMODEM protocol requested */
Xunsigned Baudrate;
Xunsigned Txwindow;	/* Control the size of the transmitted window */
Xunsigned Txwspac;	/* Spacing between zcrcq requests */
Xunsigned Txwcnt;	/* Counter used to space ack requests */
Xlong Lrxpos;		/* Receiver's last reported offset */
Xint Fromcu = 0; 	/* Were called from cu or yam */
Xint errors;
X
X/*
X * Attention string to be executed by receiver to interrupt streaming data
X *  when an error is detected.	A pause (0336) may be needed before the
X *  ^C (03) or after it.
X */
X#ifdef READCHECK
Xchar Myattn[] = { 0 };
X#else
X#ifdef USG
Xchar Myattn[] = { 03, 0336, 0 };
X#else
Xchar Myattn[] = { 0 };
X#endif
X#endif
X
XFILE *in;
X
X/* Ward Christensen / CP/M parameters - Don't change these! */
X#define ENQ 005
X#define CAN ('X'&037)
X#define XOFF ('s'&037)
X#define XON ('q'&037)
X#define SOH 1
X#define STX 2
X#define EOT 4
X#define ACK 6
X#define NAK 025
X#define CPMEOF 032
X#define WANTCRC 0103	/* send C not NAK to get crc not checksum */
X#define WANTG 0107	/* Send G not NAK to get nonstop batch xmsn */
X#define TIMEOUT (-2)
X#define RCDO (-3)
X#define RETRYMAX 10
X#define SECSIZ 128	/* cp/m's Magic Number record size */
X#define KSIZE 1024
X
Xchar Lastrx;
Xchar Crcflg;
Xint Wcsmask=0377;
Xint Verbose=0;
Xint Modem2=0;		/* XMODEM Protocol - don't send pathnames */
Xint Restricted=0;	/* restricted; no /.. or ../ in filenames */
Xint Quiet=0;		/* overrides logic that would otherwise set verbose */
Xint Ascii=0;		/* Add CR's for brain damaged programs */
Xint Fullname=0; 	/* transmit full pathname */
Xint Unlinkafter=0;	/* Unlink file after it is sent */
Xint Dottoslash=0;	/* Change foo.bar.baz to foo/bar/baz */
Xint firstsec;
Xint errcnt=0;		/* number of files unreadable */
Xint blklen=SECSIZ;		/* length of transmitted records */
Xint Optiong;		/* Let it rip no wait for sector ACK's */
Xint Noeofseen;
Xint Totsecs;		/* total number of sectors this file */
Xchar txbuf[KSIZE];
Xint Filcnt=0;		/* count of number of files opened */
Xint Lfseen=0;
Xunsigned Rxbuflen = 16384;	/* Receiver's max buffer length */
Xint Tframlen = 0;	/* Override for tx frame length */
Xint blkopt=0;		/* Override value for zmodem blklen */
Xint Rxflags = 0;
Xlong bytcnt;
Xint Wantfcs32 = TRUE;	/* want to send 32 bit FCS */
Xchar Lzconv;	/* Local ZMODEM file conversion request */
Xchar Lzmanag;	/* Local ZMODEM file management request */
Xint Lskipnocor;
Xchar Lztrans;
Xchar zconv;		/* ZMODEM file conversion request */
Xchar zmanag;		/* ZMODEM file management request */
Xchar ztrans;		/* ZMODEM file transport request */
Xint Command;		/* Send a command, then exit. */
Xchar *Cmdstr;		/* Pointer to the command string */
Xint Cmdtries = 11;
Xint Cmdack1;		/* Rx ACKs command, then do it */
Xint Exitcode = 0;
X#ifndef AMIGA
Xint Testattn;		/* Force receiver to send Attn, etc with qbf. */
X#endif
Xchar *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
Xlong Lastread;		/* Beginning offset of last buffer read */
Xint Lastn;		/* Count of last buffer read or -1 */
Xint Dontread;		/* Don't read the buffer, it's still there */
Xlong Lastsync;		/* Last offset to which we got a ZRPOS */
Xint Beenhereb4; 	/* How many times we've been ZRPOS'd same place */
X
X#ifndef AMIGA		/* No setjmp's in amiga version */
Xjmp_buf tohere; 	/* For the interrupt on RX timeout */
Xjmp_buf intrjmp;	/* For the interrupt on RX CAN */
X#endif
X
X#ifndef AMIGA
X/* called by signal interrupt or terminate to clean things up */
Xbibi(n)
X{
X	canit(); fflush(stdout); mode(0);
X	fprintf(stderr, "sz: caught signal %d; exiting\n", n);
X	if (n == SIGQUIT)
X	    abort();
X	exit(128+n);
X}
X
X/* Called when Zmodem gets an interrupt (^X) */
Xonintr()
X{
X	signal(SIGINT, SIG_IGN);
X	longjmp(intrjmp, -1);
X}
X
X#define sendline(c) putchar(c & Wcsmask)
X
X#define xsendline(c) putchar(c)
X
X#else /* AMIGA */
X
XWaitbibi(n)
Xint n;
X{
X    ConPutChar(ConWriteReq,7);
X    ConPutStr(ConWriteReq,"\nsz: Transfer aborted");
X    if( WaitC ) WaitClose();
X    bibi(n);
X}
X
XWaitClose()
X{
X ULONG IntuiMask;
X
X    IntuiMask = 1 << (Win->UserPort->mp_SigBit);
X    while(!CheckQuit()) Wait(IntuiMask);
X}
X
Xbibi(n)
X{
X    canit(); mode(0);
X    if (in) fclose(in);
X    CleanUp();
X    exit(128+n);
X}
X
XAmigaInit()
X{
X    IntuitionBase = (struct IntuitionBase *)
X			OpenLibrary("intuition.library", 33L);
X    if (IntuitionBase == NULL) {
X	puts("Unable to open 1.2 or higher intuition.library");
X	exit(1);
X    }
X    Win = OpenWindow(&nw);
X    if ( Win == NULL ) {
X	puts("Unable to open window");
X	CleanUp();
X	exit(1);
X    }
X    WinOutPut=TRUE;
X    if( OpenConsole(&ConWriteReq,&ConReadReq,Win)) {
X	puts("Couldn't open console");
X	CleanUp();
X	exit(1);
X    }
X}
X
XCleanUp()
X{
X    CloseConsole(ConReadReq,ConWriteReq);
X    if( Win )         CloseWindow(Win);
X    if(IntuitionBase) CloseLibrary(IntuitionBase);
X}
X
X#define sendline(c) xsendline(c & Wcsmask)
X
Xint nchars=0;
Xint BufferSize=128;
XUBYTE *OutBuf,*Next;
X
Xxsendline(c)
Xint c;
X{
X    *Next++=c;
X    if(++nchars==BufferSize) flushmo();
X}
X
X#undef fflush()
X
X /* Zmodem uses fflush to flush any pending output to the modem */
Xfflush(f)
XFILE *f;
X{
X
X    LWriteSer(OutBuf,nchars);
X    nchars=0;
X    Next=OutBuf;
X}
X
Xfprintf(f,s,a1,a2,a3,a4)
XFILE *f;
Xchar *s;
Xchar *a1,*a2,*a3,*a4;
X{
X char buf[256];
X
X sprintf(buf,s,a1,a2,a3,a4);
X if( WinOutPut ) ConPutStr(ConWriteReq,buf);
X else fputs(buf,f);
X}
X#endif /* AMIGA */
X
Xflushmo()
X{
X	fflush(stdout);
X}
X
Xint Zctlesc;	/* Encode control characters */
Xint Nozmodem = 0;	/* If invoked as "sb" */
Xchar *Progname = "sz";
Xint Zrwindow = 1400;	/* RX window size (controls garbage count) */
X#include "rbsb.c"       /* most of the system dependent stuff here */
X#include "zm.c"
X
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	register char *cp;
X	register npats;
X	int agcnt; char **agcv;
X	char **patts;
X#ifndef AMIGA
X	static char xXbuf[BUFSIZ];
X#endif
X	if ((cp = getenv("ZNULLS")) && *cp)
X		Znulls = atoi(cp);
X	if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
X		Restricted=TRUE;
X	chkinvok(argv[0]);
X
X	Rxtimeout = 600;
X	npats=0;
X#ifdef AMIGA
X	AmigaInit();
X#endif
X	if (argc<2)
X		usage();
X#ifndef AMIGA
X	setbuf(stdout, xXbuf);
X#endif
X	while (--argc) {
X		cp = *++argv;
X		if (*cp++ == '-' && *cp) {
X			while ( *cp) {
X				switch(*cp++) {
X				case '+':
X					Lzmanag = ZMAPND; break;
X#ifndef AMIGA
X				case '1':
X					iofd = 1; break;
X#ifdef CSTOPB
X				case '2':
X					Twostop = TRUE; break;
X#endif
X#endif
X				case '7':
X					Wcsmask=0177; break;
X				case 'a':
X					Lzconv = ZCNL;
X					Ascii = TRUE; break;
X				case 'b':
X					Lzconv = ZCBIN; break;
X#ifdef AMIGA
X				case 'B':
X					Nozmodem = TRUE; blklen=KSIZE; break;
X#endif
X				case 'C':
X					if (--argc < 1) {
X						usage();
X					}
X					Cmdtries = atoi(*++argv);
X					break;
X#ifdef AMIGA
X				case 'I':
X					InitSer = TRUE; break;
X#endif
X				case 'i':
X					Cmdack1 = ZCACK1;
X					/* **** FALL THROUGH TO **** */
X				case 'c':
X					if (--argc != 1) {
X						usage();
X					}
X					Command = TRUE;
X					Cmdstr = *++argv;
X					break;
X				case 'd':
X					++Dottoslash;
X					/* **** FALL THROUGH TO **** */
X				case 'f':
X					Fullname=TRUE; break;
X				case 'e':
X					Zctlesc = 1; break;
X#ifdef AMIGA
X				case 'h':
X					FullDuplex = FALSE; break;
X#endif
X				case 'k':
X					blklen=KSIZE; break;
X				case 'L':
X					if (--argc < 1) {
X						usage();
X					}
X					blkopt = atoi(*++argv);
X					if (blkopt<24 || blkopt>1024)
X						usage();
X					break;
X				case 'l':
X					if (--argc < 1) {
X						usage();
X					}
X					Tframlen = atoi(*++argv);
X					if (Tframlen<32 || Tframlen>1024)
X						usage();
X					break;
X#ifdef AMIGA
X				case 'm':
X					SendProtect = FALSE; break;
X#endif
X				case 'N':
X					Lzmanag = ZMNEWL;  break;
X				case 'n':
X					Lzmanag = ZMNEW;  break;
X				case 'o':
X					Wantfcs32 = FALSE; break;
X				case 'p':
X					Lzmanag = ZMPROT;  break;
X				case 'r':
X					Lzconv = ZCRESUM;
X				case 'q':
X					Quiet=TRUE; Verbose=0; break;
X#ifdef AMIGA
X				case 'Q':
X					WaitC = FALSE; break;
X#endif
X				case 't':
X					if (--argc < 1) {
X						usage();
X					}
X					Rxtimeout = atoi(*++argv);
X					if (Rxtimeout<10 || Rxtimeout>1000)
X						usage();
X					break;
X				case 'T':
X#ifndef AMIGA
X					Testattn = TRUE; break;
X#else
X					Term=TRUE; break;
X#endif
X				case 'u':
X					++Unlinkafter; break;
X				case 'v':
X					++Verbose; break;
X				case 'w':
X					if (--argc < 1) {
X						usage();
X					}
X					Txwindow = atoi(*++argv);
X					if (Txwindow < 256)
X						Txwindow = 256;
X					Txwindow = (Txwindow/64) * 64;
X					Txwspac = Txwindow/4;
X					if (blkopt > Txwspac
X					 || (!blkopt && Txwspac < 1024))
X						blkopt = Txwspac;
X					break;
X				case 'X':
X					++Modem2; break;
X				case 'Y':
X					Lskipnocor = TRUE;
X					/* **** FALLL THROUGH TO **** */
X				case 'y':
X					Lzmanag = ZMCLOB; break;
X				default:
X					usage();
X				}
X			}
X		}
X		else if ( !npats && argc>0) {
X			if (argv[0][0]) {
X				npats=argc;
X				patts=argv;
X#ifndef AMIGA
X				if ( !strcmp(*patts, "-"))
X					iofd = 1;
X#endif
X			}
X		}
X	}
X	if (npats < 1 && !Command)
X			usage();
X#ifdef AMIGA
X	if( mode(1)==ERROR) {
X	    fprintf(stderr,"Couldn't initialize serial port\n");
X	    Waitbibi(1);
X	}
X	if (Term) {
X	    fprintf(stderr,"Entering terminal mode, click on close box when ready to start file transfer\n");
X	    term();
X	}
X#endif
X	if (Verbose) {
X		if (freopen(LOGFILE, "a", stderr)==NULL) {
X			printf("Can't open log file %s\n",LOGFILE);
X			exit(0200);
X		}
X		setbuf(stderr, NULL);
X#ifdef AMIGA
X		WinOutPut=FALSE;
X#endif
X	}
X	if ((Fromcu=from_cu()) && !Quiet) {
X		if (Verbose == 0)
X			Verbose = 2;
X	}
X
X#ifndef AMIGA
X	mode(1);
X	if (signal(SIGINT, bibi) == SIG_IGN) {
X		signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
X	} else {
X		signal(SIGINT, bibi); signal(SIGKILL, bibi);
X	}
X	if ( !Fromcu)
X		signal(SIGQUIT, SIG_IGN);
X	signal(SIGTERM, bibi);
X#endif
X	if ( !Modem2) {
X		if (!Nozmodem) {
X#ifndef AMIGA
X			printf("rz\r");  fflush(stdout);
X#else
X			LWriteSer("\rrz\r",4); /* try to fire up remote rz */
X#endif
X		}
X		if (!Command && !Quiet && Verbose != 1) {
X			fprintf(stderr, "%s: %d file%s requested:\r\n",
X			 Progname, npats, npats>1?"s":"");
X			for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
X				fprintf(stderr, "%s ", *agcv++);
X			}
X			fprintf(stderr, "\r\n");
X#ifndef AMIGA /* What is that backspace doing there? */
X			printf("\r\n\bSending in Batch Mode\r\n");
X#else
X			fprintf(stderr,"\nSending in Batch Mode\n");
X#endif
X		}
X		if (!Nozmodem) {
X			stohdr(0L);
X			if (Command)
X				Txhdr[ZF0] = ZCOMMAND;
X			zshhdr(ZRQINIT, Txhdr);
X		}
X	}
X	fflush(stdout);
X
X	if (Command) {
X		if (getzrxinit()) {
X			Exitcode=0200; canit();
X		}
X		else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
X			Exitcode=0200; canit();
X		}
X	} else if (wcsend(npats, patts)==ERROR) {
X		Exitcode=0200;
X		canit();
X	}
X	fflush(stdout);
X#ifdef AMIGA
X	fprintf(stderr,"\n");
X	if( (errcnt!=0)| Exitcode) {
X	    fprintf(stderr,"Unable to complete transfer\n");
X	    ConPutChar(ConWriteReq,7);
X	}
X	else
X	    fprintf(stderr,"File transfer succesful\n");
X	if (Term) {
X	    fprintf(stderr,"Re-entering terminal mode. Click on close box to exit Sz.\n");
X	    term();
X	}
X	else if( WaitC ) {
X	    fprintf(stderr,"Click on close box to exit Sz\n");
X	    WaitClose();
X	}
X	CleanUp();
X#endif
X	mode(0);
X	exit((errcnt != 0) | Exitcode);
X	/*NOTREACHED*/
X}
X
Xwcsend(argc, argp)
Xchar *argp[];
X{
X	register n;
X
X	Crcflg=FALSE;
X	firstsec=TRUE;
X	bytcnt = -1;
X	for (n=0; n<argc; ++n) {
X		Totsecs = 0;
X		if (wcs(argp[n])==ERROR)
X			return ERROR;
X	}
X	Totsecs = 0;
X	if (Filcnt==0) {        /* bitch if we couldn't open ANY files */
X		if (1) {
X			Command = TRUE;
X			Cmdstr = "echo \"sz: Can't open any requested files\"";
X			if (getnak()) {
X				Exitcode=0200; canit();
X			}
X			if (!Zmodem)
X				canit();
X			else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
X				Exitcode=0200; canit();
X			}
X			Exitcode = 1; return OK;
X		}
X		canit();
X		fprintf(stderr,"\r\nCan't open any requested files.\r\n");
X		return ERROR;
X	}
X	if (Zmodem)
X		saybibi();
X	else if ( !Modem2)
X		wctxpn("");
X	return OK;
X}
X
Xwcs(oname)
Xchar *oname;
X{
X	register c;
X	register char *p;
X	struct stat f;
X	char name[PATHLEN];
X
X	strcpy(name, oname);
X
X#ifndef AMIGA
X	if (Restricted) {
X		/* restrict pathnames to current tree or uucppublic */
X		if ( substr(name, "../")
X		 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
X			canit();
X			fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
X			return ERROR;
X		}
X	}
X	if ( !strcmp(oname, "-")) {
X		if ((p = getenv("ONAME")) && *p)
X			strcpy(name, p);
X		else
X			sprintf(name, "s%d.sz",getpid());
X		in = stdin;
X	}
X	else
X#endif
X	     if ((in=fopen(oname, "r"))==NULL) {
X		++errcnt;
X		return OK;	/* pass over it, there may be others */
X	}
X	++Noeofseen;  Lastread = 0;  Lastn = -1; Dontread = FALSE;
X
X#ifndef AMIGA
X	/* Check for directory or block special files */
X	fstat(fileno(in), &f);
X	c = f.st_mode & S_IFMT;
X	if (c == S_IFDIR || c == S_IFBLK) {
X		fclose(in);
X		return OK;
X	}
X#else
X	stat(oname, &f);
X	fprintf(stderr, "%s: File size: %lu bytes\n", oname, f.st_size);
X#endif
X	++Filcnt;
X	switch (wctxpn(name)) {
X	case ERROR:
X		return ERROR;
X	case ZSKIP:
X		return OK;
X	}
X	if (!Zmodem && wctx(f.st_size)==ERROR)
X		return ERROR;
X	if (Unlinkafter)
X		unlink(oname);
X	return 0;
X}
X
X/*
X * generate and transmit pathname block consisting of
X *  pathname (null terminated),
X *  file length, mode time and file mode in octal
X *  as provided by the Unix fstat call.
X *  N.B.: modifies the passed name, may extend it!
X */
Xwctxpn(name)
Xchar *name;
X{
X	register char *p, *q;
X	char name2[PATHLEN];
X	struct stat f;
X#ifdef AMIGA
X	USHORT mode;
X	char *name3;
X#endif
X
X	if (Modem2) {
X#ifndef AMIGA
X		if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
X#else
X		if ((in!=stdin) && *name && stat(name, &f)!= -1) {
X#endif
X			fprintf(stderr, "Sending %s, %ld blocks: ",
X			  name, f.st_size>>7);
X		}
X		fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
X		return OK;
X	}
X	zperr("Awaiting pathname nak for %s", *name?name:"<END>");
X	if ( !Zmodem)
X		if (getnak())
X			return ERROR;
X
X	q = (char *) 0;
X	if (Dottoslash) {               /* change . to . */
X		for (p=name; *p; ++p) {
X			if (*p == '/')
X				q = p;
X			else if (*p == '.')
X				*(q=p) = '/';
X		}
X		if (q && strlen(++q) > 8) {     /* If name>8 chars */
X			q += 8; 		/*   make it .ext */
X			strcpy(name2, q);       /* save excess of name */
X			*q = '.';
X			strcpy(++q, name2);     /* add it back */
X		}
X	}
X
X#ifdef AMIGA
X	for (p = name3 = name; *p; )
X		if(*p++ == ':') {
X			name3 = p;
X			break;
X	}
X
X	for (p=name3, q=txbuf ; *p; )
X#else
X	for (p=name, q=txbuf ; *p; )
X#endif
X		if ((*q++ = *p++) == '/' && !Fullname)
X			q = txbuf;
X	*q++ = 0;
X	p=q;
X	while (q < (txbuf + KSIZE))
X		*q++ = 0;
X#ifndef AMIGA
X	if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
X		sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
X#else  /* translate AMIGA modes to UNIX modes */
X	if (!Ascii && (in!=stdin) && *name && stat(name, &f)!= -1) {
X		mode=0;
X		/*
X		 * Translate amiga file modes into UNIX file modes
X		 *
X		 */
X		if((f.st_attr&FIBF_READ)==0) mode|=0400;
X		if((f.st_attr&FIBF_WRITE)==0) mode|=0200;
X		if((f.st_attr&FIBF_EXECUTE)==0) mode|=0100;
X		/*
X		 * Unix's st_mtime starts from 1 Jan 1970 GMT,
X		 * while Manx's st_mtime starts from 1 Jan 1978
X		 *
X		 * So we adjust before sending (iff gmt_diff has been set)
X		 */
X		sprintf(p, "%lu %lo %o", f.st_size,
X	     gmt_diff_set?f.st_mtime+24*60*60*(6*365+2*366)-gmt_diff*60*60:0
X			 ,SendProtect?mode:0);
X	}
X#endif
X	/* force 1k blocks if name won't fit in 128 byte block */
X	if (txbuf[125])
X		blklen=KSIZE;
X	else {		/* A little goodie for IMP/KMD */
X		if (Zmodem)
X			blklen = SECSIZ;
X		txbuf[127] = (f.st_size + 127) >>7;
X		txbuf[126] = (f.st_size + 127) >>15;
X	}
X	if (Zmodem)
X		return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
X	if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
X		return ERROR;
X	return OK;
X}
X
Xgetnak()
X{
X	register firstch;
X
X	Lastrx = 0;
X	for (;;) {
X		switch (firstch = readock(800,1)) {
X
X		case ZPAD:
X			if (getzrxinit())
X				return ERROR;
X			Ascii = 0;
X			return FALSE;
X		case TIMEOUT:
X			zperr("Timeout on pathname");
X			return TRUE;
X		case WANTG:
X#ifdef USG
X			mode(2);        /* Set cbreak, XON/XOFF, etc. */
X#endif
X			Optiong = TRUE;
X			blklen=KSIZE;
X		case WANTCRC:
X			Crcflg = TRUE;
X		case NAK:
X			return FALSE;
X		case CAN:
X			if ((firstch = readock(20,1)) == CAN && Lastrx == CAN)
X				return TRUE;
X		default:
X			break;
X		}
X		Lastrx = firstch;
X	}
X}
X
X
Xwctx(flen)
Xlong flen;
X{
X	register int thisblklen;
X	register int sectnum, attempts, firstch;
X	long charssent;
X
X	charssent = 0;	firstsec=TRUE;	thisblklen = blklen;
X	vfile("wctx:file length=%ld", flen);
X
X	while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC
X	  && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
X		;
X	if (firstch==CAN) {
X		zperr("Receiver CANcelled");
X		return ERROR;
X	}
X	if (firstch==WANTCRC)
X		Crcflg=TRUE;
X	if (firstch==WANTG)
X		Crcflg=TRUE;
X	sectnum=0;
X	for (;;) {
X		if (flen <= (charssent + 896L))
X			thisblklen = 128;
X		if ( !filbuf(txbuf, thisblklen))
X			break;
X		if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
X			return ERROR;
X		charssent += thisblklen;
X	}
X	fclose(in);
X	attempts=0;
X	do {
X		purgeline();
X		sendline(EOT);
X		fflush(stdout);
X		++attempts;
X	}
X		while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX);
X	if (attempts == RETRYMAX) {
X		zperr("No ACK on EOT");
X		return ERROR;
X	}
X	else
X		return OK;
X}
X
Xwcputsec(buf, sectnum, cseclen)
Xchar *buf;
Xint sectnum;
Xint cseclen;	/* data length of this sector to send */
X{
X	register checksum, wcj;
X	register char *cp;
X	unsigned oldcrc;
X	int firstch;
X	int attempts;
X
X	firstch=0;	/* part of logic to detect CAN CAN */
X
X	if (Verbose>2)
X		fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
X	else if (Verbose>1)
X		fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
X	for (attempts=0; attempts <= RETRYMAX; attempts++) {
X		Lastrx= firstch;
X		sendline(cseclen==KSIZE?STX:SOH);
X		sendline(sectnum);
X		sendline(-sectnum -1);
X		oldcrc=checksum=0;
X		for (wcj=cseclen,cp=buf; --wcj>=0; ) {
X			sendline(*cp);
X			oldcrc=updcrc((0377& *cp), oldcrc);
X			checksum += *cp++;
X		}
X		if (Crcflg) {
X			oldcrc=updcrc(0,updcrc(0,oldcrc));
X			sendline((int)oldcrc>>8);
X			sendline((int)oldcrc);
X		}
X		else
X			sendline(checksum);
X#ifdef AMIGA
X		flushmo();
X#endif
X
X		if (Optiong) {
X			firstsec = FALSE; return OK;
X		}
X		firstch = readock(Rxtimeout, (Noeofseen&&sectnum) ? 2:1);
Xgotnak:
X		switch (firstch) {
X		case CAN:
X			if(Lastrx == CAN) {
Xcancan:
X				zperr("Cancelled");  return ERROR;
X			}
X			break;
X		case TIMEOUT:
X			zperr("Timeout on sector ACK"); continue;
X		case WANTCRC:
X			if (firstsec)
X				Crcflg = TRUE;
X		case NAK:
X			zperr("NAK on sector"); continue;
X		case ACK:
X			firstsec=FALSE;
X			Totsecs += (cseclen>>7);
X			return OK;
X		case ERROR:
X			zperr("Got burst for sector ACK"); break;
X		default:
X			zperr("Got %02x for sector ACK", firstch); break;
X		}
X		for (;;) {
X			Lastrx = firstch;
X			if ((firstch = readock(Rxtimeout, 2)) == TIMEOUT)
X				break;
X			if (firstch == NAK || firstch == WANTCRC)
X				goto gotnak;
X			if (firstch == CAN && Lastrx == CAN)
X				goto cancan;
X		}
X	}
X	zperr("Retry Count Exceeded");
X	return ERROR;
X}
X
X/* fill buf with count chars padding with ^Z for CPM */
Xfilbuf(buf, count)
Xregister char *buf;
X{
X	register c, m;
X
X	if ( !Ascii) {
X		m = read(fileno(in), buf, count);
X		if (m <= 0)
X			return 0;
X		while (m < count)
X			buf[m++] = 032;
X		return count;
X	}
X	m=count;
X	if (Lfseen) {
X		*buf++ = 012; --m; Lfseen = 0;
X	}
X	while ((c=getc(in))!=EOF) {
X		if (c == 012) {
X			*buf++ = 015;
X			if (--m == 0) {
X				Lfseen = TRUE; break;
X			}
X		}
X		*buf++ =c;
X		if (--m == 0)
X			break;
X	}
X	if (m==count)
X		return 0;
X	else
X		while (--m>=0)
X			*buf++ = CPMEOF;
X	return count;
X}
X/* fill buf with count chars */
Xzfilbuf(buf, count)
Xregister char *buf;
X{
X	register c, m;
X
X	m=count;
X	while ((c=getc(in))!=EOF) {
X		*buf++ =c;
X		if (--m == 0)
X			break;
X	}
X	return (count - m);
X}
X
X/* VARARGS1 */
Xvfile(f, a, b, c)
Xregister char *f;
X{
X	if (Verbose > 2) {
X		fprintf(stderr, f, a, b, c);
X		fprintf(stderr, "\n");
X	}
X}
X
X#ifndef AMIGA
Xalrm()
X{
X	longjmp(tohere, -1);
X}
X
X
X/*
X * readock(timeout, count) reads character(s) from file descriptor 0
X *  (1 <= count <= 3)
X * it attempts to read count characters. If it gets more than one,
X * it is an error unless all are CAN
X * (otherwise, only normal response is ACK, CAN, or C)
X *  Only looks for one if Optiong, which signifies cbreak, not raw input
X *
X * timeout is in tenths of seconds
X */
Xreadock(timeout, count)
X{
X	register int c;
X	static char byt[5];
X
X	if (Optiong)
X		count = 1;	/* Special hack for cbreak */
X
X	fflush(stdout);
X	if (setjmp(tohere)) {
X		zperr("TIMEOUT");
X		return TIMEOUT;
X	}
X	c = timeout/10;
X	if (c<2)
X		c=2;
X	if (Verbose>5) {
X		fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
X		byt[1] = 0;
X	}
X	signal(SIGALRM, alrm); alarm(c);
X#ifdef ONEREAD
X	c=read(iofd, byt, 1);           /* regulus raw read is unique */
X#else
X	c=read(iofd, byt, count);
X#endif
X	alarm(0);
X	if (Verbose>5)
X		fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
X	if (c<1)
X		return TIMEOUT;
X	if (c==1)
X		return (byt[0]&0377);
X	else
X		while (c)
X			if (byt[--c] != CAN)
X				return ERROR;
X	return CAN;
X}
X#else /* AMIGA */
X#ifdef BUG
X /*
X  * This code implements what the readock function is supposed to do
X  * but it breaks zmodem's YMODEM protocol for some strange reason???
X  * So I've just ifdef'd it out and replaced it with another function
X  * that forces 1 byte reads.
X  */
Xreadock(timeout,count)
Xint timeout,count;
X{
X    ULONG mask;
X    int act;
X    static char byt[5];
X
X    IOTime->tr_time.tv_secs = timeout/10;
X    IOTime->tr_time.tv_micro = 100000*(timeout%10); /* tenths of seconds */
X    IOTime->tr_node.io_Command = TR_ADDREQUEST;
X    SendIO(IOTime);
X    SendSer(count,byt);
X    mask=Wait( InSerSigMask | IOTimeSigMask | SIGBREAKF_CTRL_C);
X    if ((mask&SIGBREAKF_CTRL_C)!=0) {
X	KillIO(IOTime,mask);
X	KillIO( (struct IOStdReq *)InSer,mask);
X	Waitbibi();
X    }
X    else if ((mask&InSerSigMask)!=0) {
X	KillIO(IOTime,mask);
X	GetMsg(InSerPort);
X	act=(int)InSer->IOSer.io_Actual;
X	if (Verbose>5)
X	    fprintf(stderr, "ret cnt=%d %x %x\n", act, byt[0], byt[1]);
X	if (act==1)
X	    return (byt[0]&0377);
X	else
X	    while (act)
X		if (byt[--act] != CAN)
X		    return ERROR;
X	return CAN;
X    }
X    else  { /* it was the timer signal */
X	KillIO( (struct IOStdReq *)InSer,mask);
X	WaitIO(IOTime);
X	zperr("TIMEOUT");
X	return TIMEOUT;
X    }
X}
X#else /* KLUDGE */
Xreadock(timeout,count)
Xint timeout,count;
X{
X    int act;
X    static char byt[5];
X
X    if((byt[0]=ReadSer(timeout))==TIMEOUT) {
X	zperr("TIMEOUT");
X	return TIMEOUT;
X    }
X    act=rdchk()+1;
X    if(act>1) byt[1]=ReadSer(timeout);
X    if (Verbose>5)
X	fprintf(stderr, "ret cnt=%d %x %x\n", act, byt[0], byt[1]);
X    if (act==1)
X	return (byt[0]&0377);
X    else
X	while (act)
X	    if (byt[--act] != CAN)
X		return ERROR;
X    return CAN;
X}
X#endif /* BUG */
X#endif /* AMIGA */
X
Xreadline(n)
X{
X	return (readock(n, 1));
X}
X
Xpurgeline()
X{
X#ifdef AMIGA
X	PurgeSer();
X#else
X#ifdef USG
X	ioctl(iofd, TCFLSH, 0);
X#else
X	lseek(iofd, 0L, 2);
X#endif
X#endif /* AMIGA */
X}
X
X/* send cancel string to get the other end to shut up */
Xcanit()
X{
X	static char canistr[] = {
X	 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
X	};
X
X#ifndef AMIGA
X	printf(canistr);
X	fflush(stdout);
X#else
X	LWriteSer(canistr,strlen(canistr));
X#endif
X}
X
X/*
X * Log an error
X */
X/*VARARGS1*/
Xzperr(s,p,u)
Xchar *s, *p, *u;
X{
X	if (Verbose <= 0)
X		return;
X	fprintf(stderr, "\nRetry %d: ", errors);
X	fprintf(stderr, s, p, u);
X	fprintf(stderr, "\n");
X}
X#ifndef AMIGA
X/*
X * return 1 iff stdout and stderr are different devices
X *  indicating this program operating with a modem on a
X *  different line
X */
Xfrom_cu()
X{
X	struct stat a, b;
X	fstat(1, &a); fstat(2, &b);
X	return (a.st_rdev != b.st_rdev);
X}
X#else /* AMIGA */
Xfrom_cu()
X{
X    return TRUE;
X}
X#endif
X
X/*
X * substr(string, token) searches for token in string s
X * returns pointer to token within string if found, NULL otherwise
X */
Xchar *
Xsubstr(s, t)
Xregister char *s,*t;
X{
X	register char *ss,*tt;
X	/* search for first char of token */
X	for (ss=s; *s; s++)
X		if (*s == *t)
X			/* compare token with substring */
X			for (ss=s,tt=t; ;) {
X				if (*tt == 0)
X					return s;
X				if (*ss++ != *tt++)
X					break;
X			}
X	return NULL;
X}
X
Xchar *babble[] = {
X	"Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
X	"       (Y) = Option applies to YMODEM only",
X	"       (Z) = Option applies to ZMODEM only",
X#ifndef AMIGA
X	"Usage: sz [-12+abdefkLlNnquvwYy] [-] file ...",
X	"       sz [-12Ceqv] -c COMMAND",
X	"       sb [-12adfkquv] [-] file ...",
X	"       sx [-12akquv] [-] file",
X#else
X	"Usage: sz [-+abBdefhIkLmlNnqQTuvwXYy] file ...",
X	"       sz [-CehIqQTv] -c COMMAND",
X	"       sb [-adfhIkqQTuv] file ...",
X	"       sx [-ahIkqQTuv] file",
X#endif
X#ifndef AMIGA
X	"       1 Use stdout for modem input",
X#ifdef CSTOPB
X	"       2 Use 2 stop bits",
X#endif
X#endif
X	"       + Append to existing destination file (Z)",
X	"       a (ASCII) change NL to CR/LF",
X	"       b Binary file transfer override",
X#ifdef AMIGA
X	"       B Ymodem file transfer",
X#endif
X	"       c send COMMAND (Z)",
X	"       d Change '.' to '/' in pathnames (Y/Z)",
X	"       e Escape all control characters (Z)",
X	"       f send Full pathname (Y/Z)",
X#ifdef AMIGA
X	"       h Half duplex mode (only for Terminal mode)",
X#endif
X	"       i send COMMAND, ack Immediately (Z)",
X#ifdef AMIGA
X	"       I use serial parameters from ZMODEM.INIT file",
X#endif
X	"       k Send 1024 byte packets (Y)",
X	"       L N Limit subpacket length to N bytes (Z)",
X	"       l N Limit frame length to N bytes (l>=L) (Z)",
X#ifdef AMIGA
X	"       m Don't send file mode bits",
X#endif
X	"       n send file if source newer (Z)",
X	"       N send file if source newer or longer (Z)",
X	"       o Use 16 bit CRC instead of 32 bit CRC (Z)",
X	"       p Protect existing destination file (Z)",
X	"       r Resume/Recover interrupted file transfer (Z)",
X	"       q Quiet (no progress reports)",
X#ifdef AMIGA
X	"       Q Quit without waiting for click in close box",
X	"       T enter Terminal mode before transferring",
X#endif
X	"       u Unlink file after transmission",
X	"       v Verbose - provide debugging information",
X	"       w N Window is N bytes (Z)",
X#ifdef AMIGA
X	"       X Xmodem file transfer",
X#endif
X	"       Y Yes, overwrite existing file, skip if not present at rx (Z)",
X	"       y Yes, overwrite existing file (Z)",
X#ifndef AMIGA
X	"- as pathname sends standard input as sPID.sz or environment ONAME",
X#endif
X	""
X};
X
X#ifdef AMIGA
Xusage()
X{
X  char **pp;
X  int i,n,rows,cols,height;
X  struct Screen Scr;
X  char rep[20];
X
X    /* Expand window, to show as many lines at once as possible */
X    MoveWindow(Win,-Win->LeftEdge,-Win->TopEdge);
X    if( !GetScreenData(&Scr,sizeof(struct Screen),WBENCHSCREEN)) {
X	puts("Couldn't get screen size");
X	CleanUp();
X	exit(1);
X    }
X    rows=Scr.Height;
X    cols=Scr.Width;
X    SizeWindow(Win,cols>640?640-Win->Width:cols-Win->Width,
X		   rows-Win->Height);
X    Delay(15);  /* Wait until window is resized */
X    ConPutStr(ConWriteReq,"\2330 q"); /* get window bounds */
X    n = 0;
X    while((rep[n] = ConGetC(ConReadReq)) != 'r' && n++ < 20)
X    ;
X    height=0;
X    i=5;
X    while(rep[i]>='0' && rep[i]<='9' && i<n) {
X	height*=10;
X	height+=rep[i++]-'0';
X    }
X    for (pp=babble,i=1; **pp; ++pp,i++) {
X	fprintf(stderr, "%s\n", *pp);
X	if((i%height)==(height-1)) {
X	    WaitKey();
X	    ConPutStr(ConWriteReq,"\2331\0731\110\233\112");  /* Erase screen */
X	}
X    }
X    fprintf(stderr,"%s by Chuck Forsberg, amiga version 1.0 by Frank Harper\n",VERSION);
X    WaitKey();
X    bibi(1);
X}
X
XWaitKey()
X{
X  char ConChar;
X  ULONG mask,IntuiMask,ConInMask;
X
X    IntuiMask = 1 << (Win->UserPort->mp_SigBit);
X    ConInMask = 1 << (ConReadPort->mp_SigBit);
X    ConPutStr(ConWriteReq,"\23307\155 Press a key \23300\155");
X    QueueRead(ConReadReq,&ConChar);
X    mask=Wait(ConInMask|IntuiMask);
X    if(CheckQuit()) {       /* Hit close box? */
X	KillIO(ConReadReq);
X	bibi(1);
X    }
X    GetMsg(ConReadPort);
X}
X#else
Xusage()
X{
X	char **pp;
X	for (pp=babble; **pp; ++pp)
X		fprintf(stderr, "%s\n", *pp);
X	fprintf(stderr, "%s for %s by Chuck Forsberg\n", VERSION,OS);
X	exit(1);
X}
X#endif
X/*
X * Get the receiver's init parameters
X */
Xgetzrxinit()
X{
X	register n;
X	struct stat f;
X
X	for (n=10; --n>=0; ) {
X
X		switch (zgethdr(Rxhdr, 1)) {
X		case ZCHALLENGE:	/* Echo receiver's challenge numbr */
X			stohdr(Rxpos);
X			zshhdr(ZACK, Txhdr);
X			continue;
X		case ZCOMMAND:		/* They didn't see out ZRQINIT */
X			stohdr(0L);
X			zshhdr(ZRQINIT, Txhdr);
X			continue;
X		case ZRINIT:
X			Rxflags = 0377 & Rxhdr[ZF0];
X			Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
X			Zctlesc |= Rxflags & TESCCTL;
X			Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
X			vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
X#ifndef AMIGA
X			if ( !Fromcu)
X				signal(SIGINT, SIG_IGN);
X#ifdef USG
X			mode(2);        /* Set cbreak, XON/XOFF, etc. */
X#endif
X#ifndef READCHECK
X#ifndef USG
X			/* Use 1024 byte frames if no sample/interrupt */
X			if (Rxbuflen < 32 || Rxbuflen > 1024) {
X				Rxbuflen = 1024;
X				vfile("Rxbuflen=%d", Rxbuflen);
X			}
X#endif
X#endif
X#endif
X			/* Override to force shorter frame length */
X			if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
X				Rxbuflen = Tframlen;
X			if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
X				Rxbuflen = Tframlen;
X			vfile("Rxbuflen=%d", Rxbuflen);
X
X#ifndef AMIGA
X			/* If using a pipe for testing set lower buf len */
X			fstat(iofd, &f);
X			if ((f.st_mode & S_IFMT) != S_IFCHR
X			  && (Rxbuflen == 0 || Rxbuflen > 4096))
X				Rxbuflen = 4096;
X			/*
X			 * If input is not a regular file, force ACK's each 1024
X			 *  (A smarter strategey could be used here ...)
X			 */
X			fstat(fileno(in), &f);
X			if (((f.st_mode & S_IFMT) != S_IFREG)
X			  && (Rxbuflen == 0 || Rxbuflen > 1024))
X				Rxbuflen = 1024;
X			vfile("Rxbuflen=%d", Rxbuflen);
X#endif
X			return (sendzsinit());
X		case ZCAN:
X		case TIMEOUT:
X			return ERROR;
X		case ZRQINIT:
X			if (Rxhdr[ZF0] == ZCOMMAND)
X				continue;
X		default:
X			zshhdr(ZNAK, Txhdr);
X			continue;
X		}
X	}
X	return ERROR;
X}
X
X/* Send send-init information */
Xsendzsinit()
X{
X	register c;
X
X	if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
X		return OK;
X	errors = 0;
X	for (;;) {
X		stohdr(0L);
X		if (Zctlesc) {
X			Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
X		}
X		else
X			zsbhdr(ZSINIT, Txhdr);
X		zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
X		c = zgethdr(Rxhdr, 1);
X		switch (c) {
X		case ZCAN:
X			return ERROR;
X		case ZACK:
X			return OK;
X		default:
X			if (++errors > 19)
X				return ERROR;
X			continue;
X		}
X	}
X}
X
X/* Send file name and related info */
Xzsendfile(buf, blen)
Xchar *buf;
X{
X	register c;
X
X	for (;;) {
X		Txhdr[ZF0] = Lzconv;	/* file conversion request */
X		Txhdr[ZF1] = Lzmanag;	/* file management request */
X		if (Lskipnocor)
X			Txhdr[ZF1] |= ZMSKNOLOC;
X		Txhdr[ZF2] = Lztrans;	/* file transport request */
X		Txhdr[ZF3] = 0;
X		zsbhdr(ZFILE, Txhdr);
X		zsdata(buf, blen, ZCRCW);
Xagain:
X		c = zgethdr(Rxhdr, 1);
X		switch (c) {
X		case ZRINIT:
X			while ((c = readline(50)) > 0)
X				if (c == ZPAD) {
X					goto again;
X				}
X			/* **** FALL THRU TO **** */
X		default:
X			continue;
X		case ZCAN:
X		case TIMEOUT:
X		case ZABORT:
X		case ZFIN:
X			return ERROR;
X		case ZSKIP:
X			fclose(in); return c;
X		case ZRPOS:
X			/*
X			 * Suppress zcrcw request otherwise triggered by
X			 * lastyunc==bytcnt
X			 */
X			Lastsync = (bytcnt = Txpos = Rxpos) -1;
X			fseek(in, Rxpos, 0);
X			Dontread = FALSE;
X			return zsendfdata();
X		}
X	}
X}
X
X/* Send the data in the file */
Xzsendfdata()
X{
X	register c, e, n;
X	register newcnt;
X	register long tcount = 0;
X	int junkcount;		/* Counts garbage chars received by TX */
X	static int tleft = 6;	/* Counter for test mode */
X
X	if (Baudrate > 300)
X		blklen = 256;
X	if (Baudrate > 1200)
X		blklen = 512;
X	if (Baudrate > 2400)
X		blklen = KSIZE;
X	if (Rxbuflen && blklen>Rxbuflen)
X		blklen = Rxbuflen;
X	if (blkopt && blklen > blkopt)
X		blklen = blkopt;
X	vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
X	vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
X	Lrxpos = 0;
X	junkcount = 0;
X	Beenhereb4 = FALSE;
Xsomemore:
X#ifndef AMIGA
X	if (setjmp(intrjmp)) {
X#else
X	goto start; /* get things going right away */
X#endif
Xwaitack:
X		junkcount = 0;
X		c = getinsync(0);
Xgotack:
X		switch (c) {
X		default:
X		case ZCAN:
X			fclose(in);
X			return ERROR;
X		case ZSKIP:
X			fclose(in);
X			return c;
X		case ZACK:
X		case ZRPOS:
X			break;
X		case ZRINIT:
X			return OK;
X		}
X#ifdef READCHECK
X		/*
X		 * If the reverse channel can be tested for data,
X		 *  this logic may be used to detect error packets
X		 *  sent by the receiver, in place of setjmp/longjmp
X		 *  rdchk(fdes) returns non 0 if a character is available
X		 */
X#ifndef AMIGA
X		while (rdchk(iofd)) {
X#else
X		while (rdchk())     {
X#endif
X#ifdef SVR2
X			switch (checked)
X#else
X			switch (readline(1))
X#endif
X			{
X			case CAN:
X			case ZPAD:
X				c = getinsync(1);
X				goto gotack;
X			case XOFF:		/* Wait a while for an XON */
X			case XOFF|0200:
X				readline(100);
X			}
X		}
X#endif /* READCHECK */
X#ifndef AMIGA
X	}
X
X	if ( !Fromcu)
X		signal(SIGINT, onintr);
X#endif
Xstart:
X	newcnt = Rxbuflen;
X	Txwcnt = 0;
X	stohdr(Txpos);
X	zsbhdr(ZDATA, Txhdr);
X#ifndef AMIGA
X	/*
X	 * Special testing mode.  This should force receiver to Attn,ZRPOS
X	 *  many times.  Each time the signal should be caught, causing the
X	 *  file to be started over from the beginning.
X	 */
X	if (Testattn) {
X		if ( --tleft)
X			while (tcount < 20000) {
X				printf(qbf); fflush(stdout);
X				tcount += strlen(qbf);
X#ifdef READCHECK
X				while (rdchk(iofd)) {
X#ifdef SVR2
X					switch (checked)
X#else
X					switch (readline(1))
X#endif
X					{
X					case CAN:
X					case ZPAD:
X#ifdef TCFLSH
X						ioctl(iofd, TCFLSH, 1);
X#endif
X						goto waitack;
X					case XOFF:	/* Wait for XON */
X					case XOFF|0200:
X						readline(100);
X					}
X				}
X#endif /* READCHECK */
X			}
X		signal(SIGINT, SIG_IGN); canit();
X		sleep(3); purgeline(); mode(0);
X		printf("\nsz: Tcount = %ld\n", tcount);
X		if (tleft) {
X			printf("ERROR: Interrupts Not Caught\n");
X			exit(1);
X		}
X		exit(0);
X	}
X#endif
X
X	do {
X		if (Dontread) {
X			n = Lastn;
X		} else {
X			n = zfilbuf(txbuf, blklen);
X			Lastread = Txpos;  Lastn = n;
X		}
X		Dontread = FALSE;
X		if (n < blklen)
X			e = ZCRCE;
X		else if (junkcount > 3)
X			e = ZCRCW;
X		else if (bytcnt == Lastsync)
X			e = ZCRCW;
X		else if (Rxbuflen && (newcnt -= n) <= 0)
X			e = ZCRCW;
X		else if (Txwindow && (Txwcnt += n) >= Txwspac) {
X			Txwcnt = 0;  e = ZCRCQ;
X		}
X		else
X			e = ZCRCG;
X		if (Verbose>1)
X			fprintf(stderr, "\r%7ld ZMODEM%s    ",
X			  Txpos, Crc32t?" CRC-32":"");
X		zsdata(txbuf, n, e);
X		bytcnt = Txpos += n;
X		if (e == ZCRCW)
X			goto waitack;
X#ifdef READCHECK
X		/*
X		 * If the reverse channel can be tested for data,
X		 *  this logic may be used to detect error packets
X		 *  sent by the receiver, in place of setjmp/longjmp
X		 *  rdchk(fdes) returns non 0 if a character is available
X		 */
X		fflush(stdout);
X#ifndef AMIGA
X		while (rdchk(iofd)) {
X#else
X		while (rdchk()) {
X#endif
X#ifdef SVR2
X			switch (checked)
X#else
X			switch (readline(1))
X#endif
X			{
X			case CAN:
X			case ZPAD:
X				c = getinsync(1);
X				if (c == ZACK)
X					break;
X#ifdef TCFLSH
X				ioctl(iofd, TCFLSH, 1);
X#endif
X				/* zcrce - dinna wanna starta ping-pong game */
X				zsdata(txbuf, 0, ZCRCE);
X				goto gotack;
X			case XOFF:		/* Wait a while for an XON */
X			case XOFF|0200:
X				readline(100);
X			default:
X				++junkcount;
X			}
X		}
X#endif	/* READCHECK */
X		if (Txwindow) {
X			while ((tcount = Txpos - Lrxpos) >= Txwindow) {
X				vfile("%ld window >= %u", tcount, Txwindow);
X				if (e != ZCRCQ)
X					zsdata(txbuf, 0, e = ZCRCQ);
X				c = getinsync(1);
X				if (c != ZACK) {
X#ifdef TCFLSH
X					ioctl(iofd, TCFLSH, 1);
X#endif
X					zsdata(txbuf, 0, ZCRCE);
X					goto gotack;
X				}
X			}
X			vfile("window = %ld", tcount);
X		}
X	} while (n == blklen);
X#ifndef AMIGA
X	if ( !Fromcu)
X		signal(SIGINT, SIG_IGN);
X#endif
X
X	for (;;) {
X		stohdr(Txpos);
X		zsbhdr(ZEOF, Txhdr);
X		switch (getinsync(0)) {
X		case ZACK:
X			continue;
X		case ZRPOS:
X			goto somemore;
X		case ZRINIT:
X			return OK;
X		case ZSKIP:
X			fclose(in);
X			return c;
X		default:
X			fclose(in);
X			return ERROR;
X		}
X	}
X}
X
X/*
X * Respond to receiver's complaint, get back in sync with receiver
X */
Xgetinsync(flag)
X{
X	register c;
X
X	for (;;) {
X#ifndef AMIGA
X		if (Testattn) {
X			printf("\r\n\n\n***** Signal Caught *****\r\n");
X			Rxpos = 0; c = ZRPOS;
X		} else
X#endif
X			c = zgethdr(Rxhdr, 0);
X		switch (c) {
X		case ZCAN:
X		case ZABORT:
X		case ZFIN:
X		case TIMEOUT:
X			return ERROR;
X		case ZRPOS:
X			/* ************************************* */
X			/*  If sending to a modem beuufer, you	 */
X			/*   might send a break at this point to */
X			/*   dump the modem's buffer.            */
X			if (Lastn >= 0 && Lastread == Rxpos) {
X				Dontread = TRUE;
X			} else {
X				clearerr(in);   /* In case file EOF seen */
X				fseek(in, Rxpos, 0);
X			}
X			bytcnt = Lrxpos = Txpos = Rxpos;
X			if (Lastsync == Rxpos) {
X				if (++Beenhereb4 > 4)
X					if (blklen > 256)
X						blklen /= 2;
X			}
X			Lastsync = Rxpos;
X			return c;
X		case ZACK:
X			Lrxpos = Rxpos;
X			if (flag || Txpos == Rxpos)
X				return ZACK;
X			continue;
X		case ZRINIT:
X		case ZSKIP:
X			fclose(in);
X			return c;
X		case ERROR:
X		default:
X			zsbhdr(ZNAK, Txhdr);
X			continue;
X		}
X	}
X}
X
X
X/* Say "bibi" to the receiver, try to do it cleanly */
Xsaybibi()
X{
X	for (;;) {
X		stohdr(0L);             /* CAF Was zsbhdr - minor change */
X		zshhdr(ZFIN, Txhdr);    /*  to make debugging easier */
X		switch (zgethdr(Rxhdr, 0)) {
X		case ZFIN:
X			sendline('O'); sendline('O'); flushmo();
X		case ZCAN:
X		case TIMEOUT:
X			return;
X		}
X	}
X}
X
X/* Local screen character display function */
Xbttyout(c)
X{
X#ifndef AMIGA
X	if (Verbose)
X#else
X	if (Verbose>2)
X#endif
X		putc(c, stderr);
X}
X
X/* Send command and related info */
Xzsendcmd(buf, blen)
Xchar *buf;
X{
X	register c;
X	long cmdnum;
X
X#ifndef AMIGA
X	cmdnum = getpid();
X#endif
X	errors = 0;
X	for (;;) {
X		stohdr(cmdnum);
X		Txhdr[ZF0] = Cmdack1;
X		zsbhdr(ZCOMMAND, Txhdr);
X		zsdata(buf, blen, ZCRCW);
Xlisten:
X		Rxtimeout = 100;		/* Ten second wait for resp. */
X		c = zgethdr(Rxhdr, 1);
X
X		switch (c) {
X		case ZRINIT:
X			goto listen;	/* CAF 8-21-87 */
X		case ERROR:
X		case TIMEOUT:
X			if (++errors > Cmdtries)
X				return ERROR;
X			continue;
X		case ZCAN:
X		case ZABORT:
X		case ZFIN:
X		case ZSKIP:
X		case ZRPOS:
X			return ERROR;
X		default:
X			if (++errors > 20)
X				return ERROR;
X			continue;
X		case ZCOMPL:
X			Exitcode = Rxpos;
X			saybibi();
X			return OK;
X		case ZRQINIT:
X			vfile("******** RZ *******");
X#ifndef AMIGA
X			system("rz");
X#else
X			Execute("rz",0L,0L);
X#endif
X			vfile("******** SZ *******");
X			goto listen;
X		}
X	}
X}
X
X/*
X * If called as sb use YMODEM protocol
X */
Xchkinvok(s)
Xchar *s;
X{
X	register char *p;
X
X	p = s;
X	while (*p == '-')
X		s = ++p;
X	while (*p)
X		if (*p++ == '/')
X			s = p;
X	if (*s == 'v') {
X		Verbose=1; ++s;
X	}
X	Progname = s;
X	if (s[0]=='s' && s[1]=='b') {
X		Nozmodem = TRUE; blklen=KSIZE;
X	}
X	if (s[0]=='s' && s[1]=='x') {
X		Modem2 = TRUE;
X	}
X}
X/* End of sz.c */
SHAR_EOF
echo "End of archive 3 (of 9)"
# if you want to concatenate archives, remove anything after this line
exit