[comp.sources.atari.st] v01i044: zmdm -- terminal program with file transfer part04/08

koreth@ssyx.ucsc.edu (Steven Grimm) (05/30/88)

Submitted-by: bammi@mandrill.ces.cwru.edu (Jwahar R. Bammi)
Posting-number: Volume 1, Issue 44
Archive-name: zmdm/part04

#!/bin/sh
# this is part 4 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file RZ.C continued
#
CurArch=4
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file RZ.C"
sed 's/^X//' << 'SHAR_EOF' >> RZ.C
X	fprintf(STDERR,"	     transfer if the dest. file exists (ZMODEM ONLY)\n\n");
X
X
X	if(fout != -1)
X	{
X		if (stfclose(fout) != 0)
X		{
X			fprintf(STDERR, "\r\nfile close ERROR\n");
X		}
X		fout = (-1);
X	}
X
X#ifdef RDEBUG
X	if(logf != (FILE *)NULL)
X		fclose(logf);
X#endif
X
X	return(1);
X}
X
X
X/*
X * Let's receive something already.
X */
Xwcreceive(argc, argp)
Xint argc;
Xchar **argp;
X{
X	register int c;
X
X	if (Batch || argc==0)
X	{
X		Crcflg=(Wcsmask==0377);
X		if ( !Quiet)
X#ifndef REMOTE
X			fprintf(STDERR, "\n%s: ready (CTRL-C to cancel)\n\n",
X				Progname);
X#else
X			fprintf(STDERR, "\n%s: ready\n\n",
X				Progname);
X#endif
X		if (c=tryz())
X		{
X			if (c == ZCOMPL)
X				return OK;
X			if (c == ERROR)
X				goto fubar;
X			c = rzfiles();
X			if (c)
X				goto fubar;
X		}
X		else
X		{
X			for (;;)
X			{
X				if (wcrxpn(secbuf)== ERROR)
X					goto fubar;
X				if (secbuf[0]==0)
X					return OK;
X				if (procheader(secbuf) == ERROR)
X					goto fubar;
X				if (wcrx()==ERROR)
X					goto fubar;
X			}
X		}
X	} 
X	else
X	{
X		Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
X
X		strcpy(Pathname, *argp);
X#ifndef REMOTE
X		fprintf(STDERR, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n",
X			Progname, Pathname);
X#else
X		fprintf(STDERR, "\n%s: ready to receive %s\n\n",
X			Progname, Pathname);
X#endif
X
X#ifdef RDEBUG
X		if(logf != (FILE *)NULL)
X			fprintf(logf, "\nrz: ready to receive %s ", Pathname);
X#endif
X
X		if((fout = stfopen(Pathname,"w")) <= 0)
X			return ERROR;
X		if (wcrx()==ERROR)
X			goto fubar;
X	}
X	return OK;
X
Xfubar:
X	canit();
X
X	if (fout != -1)
X	{
X		if (stfclose(fout) != 0)
X		{
X			fprintf(STDERR, "\r\nfile close ERROR\n");
X		}
X		fout = (-1);
X	}
X
X	return ERROR;
X}
X
X
X/*
X * Fetch a pathname from the other end as a C ctyle ASCIZ string.
X * Length is indeterminate as long as less than Blklen
X * A null string represents no more files (YMODEM)
X */
Xwcrxpn(rpn)
Xchar *rpn;	/* receive a pathname */
X{
X	register int c;
X
X	PURGELINE;
X
Xet_tu:
X	Firstsec=TRUE;  Eofseen=FALSE;
X	sendline(Crcflg?WANTCRC:NAK);
X	Lleft=0;	/* Do read next time ... */
X	while ((c = wcgetsec(rpn, 100)) != 0)
X	{
X		llog( "Pathname fetch returned %d\n", c);
X		if (c == WCEOT)
X		{
X			sendline(ACK);
X			Lleft=0;	/* Do read next time ... */
X			readline(1);
X			goto et_tu;
X		}
X		return ERROR;
X	}
X	sendline(ACK);
X	return OK;
X}
X
X/*
X * Adapted from CMODEM13.C, written by
X * Jack M. Wierda and Roderick W. Hart
X */
X
Xwcrx()
X{
X	register int sectnum, sectcurr;
X	register char sendchar;
X	int cblklen;			/* bytes to dump this block */
X
X	Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
X	sendchar=Crcflg?WANTCRC:NAK;
X
X	for (;;)
X	{
X		sendline(sendchar);	/* send it now, we're ready! */
X		Lleft=0;	/* Do read next time ... */
X		sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
X		report(sectcurr);
X		if (sectcurr==(sectnum+1 &Wcsmask))
X		{
X			sectnum++;
X			cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
X			if (putsec(secbuf, cblklen)==ERROR)
X				return ERROR;
X			if ((Bytesleft-=cblklen) < 0)
X				Bytesleft = 0;
X			sendchar=ACK;
X		}
X		else if (sectcurr==(sectnum&Wcsmask))
X		{
X			log2( "Received dup Sector\n");
X			sendchar=ACK;
X		}
X		else if (sectcurr==WCEOT)
X		{
X			if (closeit(0L))
X				return ERROR;
X			sendline(ACK);
X			Lleft=0;	/* Do read next time ... */
X			return OK;
X		}
X		else if (sectcurr==ERROR)
X			return ERROR;
X		else
X		{
X			log2( "Sync Error\n");
X			return ERROR;
X		}
X	}
X}
X
X
X/*
X * Wcgetsec fetches a Ward Christensen type sector.
X * Returns sector number encountered or ERROR if valid sector not received,
X * or CAN CAN received
X * or WCEOT if eot sector
X * time is timeout for first char, set to 4 seconds thereafter
X ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
X *    (Caller must do that when he is good and ready to get next sector)
X */
Xwcgetsec(rxbuf, maxtime)
Xchar *rxbuf;
Xint maxtime;
X{
X	register int checksum, wcj, firstch;
X	register unsigned int oldcrc;
X	register char *p;
X	int sectcurr;
X
X	for (Lastrx=errors=0; errors<RETRYMAX; errors++)
X	{
X
X		if ((firstch=readline(maxtime))==STX)
X		{
X			Blklen=KSIZE; goto get2;
X		}
X		if (firstch==SOH)
X		{
X			Blklen=SECSIZ;
Xget2:
X			sectcurr=readline(1);
X			if ((sectcurr+(oldcrc=readline(1)))==Wcsmask)
X			{
X				oldcrc=checksum=0;
X				for (p=rxbuf,wcj=Blklen; --wcj>=0; )
X				{
X					if ((firstch=readline(1)) < 0)
X						goto bilge;
X					oldcrc=updcrc(firstch, oldcrc);
X					checksum += (*p++ = firstch);
X				}
X				if ((firstch=readline(1)) < 0)
X					goto bilge;
X				if (Crcflg)
X				{
X					oldcrc=updcrc(firstch, oldcrc);
X					if ((firstch=readline(1)) < 0)
X						goto bilge;
X					oldcrc=updcrc(firstch, oldcrc);
X					if (oldcrc & 0xFFFF)
X						llog("CRC=0%o\n", oldcrc);
X					else
X					{
X						Firstsec=FALSE;
X						return sectcurr;
X					}
X				}
X				else if (((checksum-firstch)&Wcsmask)==0)
X				{
X					Firstsec=FALSE;
X					return sectcurr;
X				}
X				else
X					log2( "Checksum Error\n");
X			}
X			else
X				log2("Sector number garbled 0%o 0%o\n",
X				 sectcurr, oldcrc);
X		}
X		/* make sure eot really is eot and not just mixmash */
X
X		else if (firstch==EOT && Lleft==0)
X			return WCEOT;
X
X		else if (firstch==CAN)
X		{
X			if (Lastrx==CAN)
X			{
X				log2( "Sender CANcelled\n");
X				return ERROR;
X			}
X			else
X			{
X				Lastrx=CAN;
X				continue;
X			}
X		}
X		else if (firstch==TIMEOUT)
X		{
X			if (Firstsec)
X				goto humbug;
Xbilge:
X			log2( "Timeout\n");
X		}
X		else
X			llog( "Got 0%o sector header\n", firstch);
X
Xhumbug:
X		Lastrx=0;
X		while(readline(1)!=TIMEOUT)
X			;
X		if (Firstsec)
X		{
X			sendline(Crcflg?WANTCRC:NAK);
X			Lleft=0;	/* Do read next time ... */
X		}
X		else
X		{
X			maxtime=40; sendline(NAK);
X			Lleft=0;	/* Do read next time ... */
X		}
X	}
X	/* try to stop the bubble machine. */
X	canit();
X	return ERROR;
X}
X
X
X
X
X/*
X * Process incoming file information header
X */
Xprocheader(name)
Xchar *name;
X{
X	register char  *p;
X	register int dot;
X	char openmode[4];
X	extern int strlen();
X
X	/* convert to ST style path names */
X	for( p = name; *p != '\0'; p++)
X	{
X		if(*p == '/')
X			*p = '\\';
X	}
X	
X	/* pick out the last extention in the filename in each part of path */
X	while(p != name)
X	{
X		dot = 0; p-- ;
X		while((p != name) && (*p != '\\'))
X		{
X			if(*p == '.')
X			{
X				if(dot == 0)
X				{
X					dot = 1;
X				}
X				else
X				{
X				   /* replace all but the last dot with '_' */
X					*p = '_';
X				}
X			}
X			p--;
X		}
X	}
X				
X	/* set default parameters and overrides */
X	strcpy(openmode,"w");
X
X	Thisbinary = isbinary(name);
X
X	if (Lzmanag)
X		zmanag = Lzmanag;
X
X	/*
X	 *  Process ZMODEM remote file management requests
X	 */
X	if ( zconv == ZCNL)	/* Remote ASCII override */
X		Thisbinary = 0;
X	if (zconv == ZCBIN)	/* Remote Binary override */
X		++Thisbinary;
X	else if (zmanag == ZMAPND)
X		strcpy(openmode, "a");
X
X	if (ForceBinary == TRUE )	/* local binary force override */
X		++Thisbinary;
X
X	/* ZMPROT check for existing file */
X	if (zmanag == ZMPROT && existf(name, "r"))
X	{
X		return ERROR;
X	}
X
X/* ATARI ST NOTE:
X *	We will not accept rooted paths ie. paths that begin in '\' or '.\'
X *	If the incoming filename is rooted, we skip the beginning
X *	'\'   '.\'  or  '..\'
X */
X
X	if( (name[0] == '\\') || (name[0] == '.')  )
X	{
X		/* skip over the leading stuff */
X		if(name[0] == '\\')
X			name = &name[1];
X		else
X		{
X			if(name[1] == '.')
X				name = &name[3];  /* Skip the "..\" */
X			else
X				name = &name[2];  /* Skip the ".\"  */
X		}
X	}
X
X	/* ST addition, create any dierctories in the path that don't exist */
X	if( pathensure(name) == ERROR)
X		return ERROR;
X
X	Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
X
X	p = name + 1 + strlen(name);
X	if (*p)
X	{	/* file coming from Unix or DOS system */
X		sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
X/* NA to atari
X			if (Filemode & UNIXFILE)
X				++Thisbinary; 
X*/
X#ifndef REMOTE
X		if (Verbose)
X		{
X			fprintf(STDERR,
X			"\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\
X\tModTime: %ld\n\tMode:\t%o\n\tBufSize: %ld\n\n",
X			  name, Bytesleft, Modtime, Filemode, (long)BBUFSIZ);
X
X#ifdef RDEBUG
X			if(logf != (FILE *)NULL)
X				fprintf(logf,  "Incoming: %s %ld %lo %o\n",
X				  name, Bytesleft, Modtime, Filemode);
X#endif
X
X		}
X#endif /* REMOTE */
X
X	}
X	else
X	{		/* File coming from CP/M system */
X		for (p=name; *p; ++p)		/* change / to _ */
X			if ( *p == '/')
X				*p = '_';
X
X		if ( *--p == '.')		/* zap trailing period */
X			*p = 0;
X	}
X	
X	strcpy(Pathname, name);
X#ifndef REMOTE
X	if (Verbose)
X	{
X		fprintf(STDERR,  "Receiving %s %s [mode %s]\n\n",
X		  name, Thisbinary?"BIN":"ASCII", openmode);
X
X#ifdef RDEBUG
X		if(logf != (FILE *)NULL)
X			fprintf(logf,  "Receiving %s %s %s\n",
X			  name, Thisbinary?"BIN":"ASCII", openmode);
X#endif
X
X	}
X#endif /* REMOTE */
X
X	if ((fout=stfopen(name, openmode)) <= 0)
X		return ERROR;
X
X	return OK;
X}
X
X/*
X * Putsec writes the n characters of buf to receive file fout.
X *  If not in binary mode,  all characters
X *  starting with CPMEOF are discarded.
X */
Xputsec(buf, n)
Xunsigned char *buf;
Xregister int n;
X{
X	register unsigned char *p;
X
X	if (Thisbinary)
X	{
X		for (p=buf; --n>=0; p++ )
X		{
X			if(stputc( *p, fout) < 0)
X			{
X				fprintf(STDERR, "\r\nError while Writing file\n");
X				return ERROR;
X			}
X		}
X	}
X	else
X	{
X		if (Eofseen)
X			return OK;
X
X		for (p=buf; --n>=0; p++ )
X		{
X			if (*p == CPMEOF)
X			{
X				Eofseen=TRUE;
X				return OK;
X			}
X			if(*p == '\n')
X			{
X				if(stputc('\r' ,fout) < 0)
X				{
X					fprintf(STDERR, "\r\nError while Writing file\n");
X					return ERROR;
X				}
X			}
X			if(stputc(*p ,fout) < 0)
X			{
X				fprintf(STDERR,"\r\nError while Writing file\n");
X				return ERROR;
X			}
X		}
X	}
X
X	return OK;
X}
X
X/*
X * Log an error only if high verbose
X */
X/*VARARGS1*/
Xllog(s,p,u)
Xchar *s;
Xint p, u;
X{
X	if (Verbose < 3)
X		return;
X#ifdef RDEBUG
X	fprintf(logf, "error %d: ", errors);
X	fprintf(logf, s, p, u);
X#endif
X
X	fprintf(STDERR, "\nerror %d: ", errors);
X	fprintf(STDERR, s, p, u);
X}
X
X
X
X#ifndef STANDALONE
X/*
X * If called as rb use YMODEM protocol
X */
Xchkinvok(s)
Xchar *s;
X{
X	Progname = s;
X	if (s[0]=='r' && s[1]=='b')
X		Nozmodem = TRUE;
X}
X#endif
X
X/*
X * Initialize for Zmodem receive attempt, try to activate Zmodem sender
X *  Handles ZSINIT frame
X *  Return ZFILE if Zmodem filename received, -1 on error,
X *   ZCOMPL if transaction finished,  else 0
X */
Xtryz()
X{
X	register int n;
X	register int cmdzack1flg;
X
X	if (Nozmodem)		/* Check for "rb" program name */
X		return 0;
X
X
X	for (n=Zmodem?10:5; --n>=0; )
X	{
X		/* Set buffer length (0) and capability flags */
X		stohdr(0L);
X		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; /* of course we can break */
X
X		zshhdr(tryzhdrtype, Txhdr);
X/*		zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); */
Xagain:
X		switch (zgethdr(Rxhdr, 0))
X		{
X		case ZRQINIT:
X			continue;
X		case ZEOF:
X			continue;
X		case TIMEOUT:
X			continue;
X		case ZFILE:
X			zconv = Rxhdr[ZF0];
X			zmanag = Rxhdr[ZF1];
X			ztrans = Rxhdr[ZF2];
X			tryzhdrtype = ZRINIT;
X			Badclose = FALSE;
X			if (zrdata(secbuf, KSIZE) == GOTCRCW)
X				return ZFILE;
X			zshhdr(ZNAK, Txhdr);
X			goto again;
X		case ZSINIT:
X			if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
X			{
X				zshhdr(ZACK, Txhdr);
X				goto again;
X			}
X			zshhdr(ZNAK, Txhdr);
X			goto again;
X		case ZFREECNT:
X			stohdr(~0L);
X			zshhdr(ZACK, Txhdr);
X			goto again;
X		case ZCOMMAND:
X			cmdzack1flg = Rxhdr[ZF0];
X			if (zrdata(secbuf, KSIZE) == GOTCRCW)
X			{
X				if (cmdzack1flg & ZCACK1)
X					stohdr(0L);
X				else
X					stohdr((long)sys2(secbuf));
X				PURGELINE;	/* dump impatient questions */
X				do {
X					zshhdr(ZCOMPL, Txhdr);
X				}
X				while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN);
X				ackbibi();
X				if (cmdzack1flg & ZCACK1)
X					exec2(secbuf);
X				return ZCOMPL;
X			}
X			zshhdr(ZNAK, Txhdr); goto again;
X		case ZCOMPL:
X			goto again;
X		default:
X			continue;
X		case ZFIN:
X			ackbibi(); return ZCOMPL;
X		case ZCAN:
X			return ERROR;
X		}
X	}
X	return 0;
X}
X
X/*
X * Receive 1 or more files with ZMODEM protocol
X */
Xrzfiles()
X{
X	register int c;
X
X	for (;;) {
X		switch (c = rzfile()) {
X		case ZEOF:
X		case ZSKIP:
X			switch (tryz()) {
X			case ZCOMPL:
X				return OK;
X			default:
X				return ERROR;
X			case ZFILE:
X				break;
X			}
X			continue;
X		default:
X			return c;
X		case ERROR:
X			return ERROR;
X		}
X	}
X}
X
X/*
X * Receive a file with ZMODEM protocol
X *  Assumes file name frame is in secbuf
X */
Xrzfile()
X{
X	register int c, n;
X	long rxbytes;
X	extern void rd_time();
X
X	Eofseen=FALSE;
X	if (procheader(secbuf) == ERROR) {
X		return (tryzhdrtype = ZSKIP);
X/*		zshhdr(ZSKIP, Txhdr);
X		return ZSKIP; */
X	}
X
X	n = 10; rxbytes = 0L;
X
X	Supexec(rd_time);
X	start_time = pr_time;
X
X	for (;;)
X	{
X		stohdr(rxbytes);
X		zshhdr(ZRPOS, Txhdr);
Xnxthdr:
X		switch (c = zgethdr(Rxhdr, 0)) {
X		default:
X			vfile("rzfile: zgethdr returned %d", c);
X			return ERROR;
X		case ZNAK:
X		case TIMEOUT:
X			if ( --n < 0)
X			{
X				vfile("rzfile: zgethdr returned %d", c);
X				return ERROR;
X			}
X		case ZFILE:
X			zrdata(secbuf, KSIZE);
X			continue;
X		case ZEOF:
X			/* ++jrb */
X			if (rclhdr(Rxhdr) != rxbytes)
X			{
X				/*
X			         * Ignore eof if it's at wrong place - force
X			         *  a timeout because the eof might have gone
X			         *  out before we sent our zrpos.
X			         */
X
X			        errors = 0;  goto nxthdr;
X			}
X/* --jrb
X			if (rclhdr(Rxhdr) != rxbytes)
X			{
X				continue;
X			}
X-- */
X			if (closeit(rxbytes))
X			{
X				tryzhdrtype = ZFERR;
X				Badclose = TRUE;
X				vfile("rzfile: closeit returned <> 0");
X				return ERROR;
X			}
X			vfile("rzfile: normal EOF");
X			return c;
X		case ERROR:	/* Too much garbage in header search error */
X			if ( --n < 0)
X			{
X				vfile("rzfile: zgethdr returned %d", c);
X				return ERROR;
X			}
X			zmputs(Attn);
X			continue;
X		case ZDATA:
X			n = 10;
X			if (rclhdr(Rxhdr) != rxbytes)
X			{
X				zmputs(Attn);
X				continue;
X			}
Xmoredata:
X			switch (c = zrdata(secbuf, KSIZE))
X			{
X			case ZCAN:
X				vfile("rzfile: zgethdr returned %d", c);
X				return ERROR;
X			case ERROR:	/* CRC error */
X				if ( --n < 0)
X				{
X					vfile("rzfile: zgethdr returned %d", c);
X					return ERROR;
X				}
X				zmputs(Attn);
X				continue;
X			case TIMEOUT:
X				if ( --n < 0)
X				{
X					vfile("rzfile: zgethdr returned %d", c);
X					return ERROR;
X				}
X				continue;
X			case GOTCRCW:
X				if(putsec(secbuf, Rxcount) == ERROR)
X					return ERROR;
X				rxbytes += Rxcount;
X				lreport(rxbytes);
X				stohdr(rxbytes);
X				zshhdr(ZACK, Txhdr);
X				goto nxthdr;
X			case GOTCRCQ:
X				if(putsec(secbuf, Rxcount) == ERROR)
X					return ERROR;
X				rxbytes += Rxcount;
X				lreport(rxbytes);
X				stohdr(rxbytes);
X				zshhdr(ZACK, Txhdr);
X				goto moredata;
X			case GOTCRCG:
X				if(putsec(secbuf, Rxcount) == ERROR)
X					return ERROR;
X				rxbytes += Rxcount;
X				lreport(rxbytes);
X				goto moredata;
X			case GOTCRCE:
X				if(putsec(secbuf, Rxcount) == ERROR)
X					return ERROR;
X				rxbytes += Rxcount;
X				lreport(rxbytes);
X				goto nxthdr;
X			}
X		}
X	}
X}
X
X/*
X * Send a string to the modem, processing for \336 (sleep 1 sec)
X *   and \335 (break signal)
X */
Xzmputs(s)
Xchar *s;
X{
X	register int c;
X
X	while (*s) {
X		switch (c = *s++) {
X		case '\336':
X			stsleep(1); continue;
X		case '\335':
X			sendbrk(); continue;
X		default:
X			sendline(c);
X		}
X	}
X}
X
X
X
X/*
X * Close the receive dataset, return OK or ERROR
X */
Xcloseit(rxbytes)
Xlong rxbytes;
X{
X	unsigned int timep[2];
X	long end_time;
X	extern void rd_time();
X
X	if (stfclose(fout) != 0) {
X		fprintf(STDERR, "\r\nfile close ERROR\n");
X		return ERROR;
X	}
X	fout = (-1);
X
X	Supexec(rd_time);
X	end_time = pr_time;
X
X	if (Modtime) {
X		unix2st(Modtime, &timep[0], &timep[1]);
X		touch(Pathname, timep);
X	}
X
X	/* if it is read only by owner on remote, then it is set
X	 * to read only on the ST, all other file modes are
X	 * irrelevant.
X	 */
X	if (Filemode)
X	{
X		unsigned int fmode;
X
X		fmode = (unsigned int)(Filemode & 000777);
X		if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) )
X		{
X			/* it is readonly by owner on the remote, so
X			 * make it read only on the ST too
X			 */
X			Fattrib(Pathname, 1, 0x01);
X		}
X	}
X#ifndef REMOTE
X	if(rxbytes != 0L)
X	    fprintf(STDERR,"\n\n%s Closed\nTransfer Time %ld secs.\tfor %ld bytes\
X\tApprox %ld cps\n\n", Pathname, (end_time - start_time)/200L, rxbytes,
Xrxbytes/((end_time - start_time)/200L));
X	else
X		fprintf(STDERR,"\n\n%s Closed\n\n", Pathname);
X#endif
X	lsct = 1;
X	return OK;
X}
X
X/*
X * Ack a ZFIN packet, let byegones be byegones
X */
Xackbibi()
X{
X	register int n;
X
X	vfile("ackbibi:");
X	Readnum = 1;
X	stohdr(0L);
X	for (n=4; --n>=0; )
X	{
X		zshhdr(ZFIN, Txhdr);
X		for (;;) {
X			switch (readline(100))
X			{
X			case 'O':
X				readline(1);	/* Discard 2nd 'O' */
X				/* ***** FALL THRU TO ***** */
X			case TIMEOUT:
X				vfile("ackbibi complete");
X				return;
X			default:
X				break;
X			}
X		}
X	}
X}
X
X
X/*
X * Strip leading ! if present, do shell escape. 
X */
Xsys2(s)
Xregister char *s;
X{
X	if (*s == '!')
X		++s;
X	return stsystem(s);
X}
X/*
X * Strip leading ! if present, do exec.
X */
Xexec2(s)
Xchar *s;
X{
X/** Are you kidding
X	if (*s == '!')
X		++s;
X	mode(0);
X	execl("/bin/sh", "sh", "-c", s); 
X**/
X}
X
X/*
X * Touch a file
X */
X#ifndef MANX
X#undef Fdatime		/* There exist brain damaged versions of osbind.h */
X#define	Fdatime(a,b,c)	gemdos(0x57,a,b,c)
X#endif /* MANX has its _Gemdos stuff */
X
Xtouch(name, timep)
Xchar *name;
Xunsigned int *timep;
X{
X	register int handl;
X
X	if((handl = Fopen(name, 0)) < 0)
X	{
X#ifndef REMOTE
X		fprintf(STDERR,"*WARNING* Could not set file modification time for %s\n",
X			name);
X#endif
X		return;
X	}
X
X
X	Fdatime(timep, handl, 1);
X	Fclose(handl);
X}
X
X/* -eof- */
SHAR_EOF
echo "File RZ.C is complete"
chmod 0600 RZ.C || echo "restore of RZ.C fails"
echo "x - extracting RZLNK (Text)"
sed 's/^X//' << 'SHAR_EOF' > RZLNK &&
Xc:\lib\gemstart.o common.o rz.o util.o tyme.o zm.o fileio.o
Xc:\lib\osbind.o c:\lib\gemlib c:\lib\libf
SHAR_EOF
chmod 0600 RZLNK || echo "restore of RZLNK fails"
echo "x - extracting SZ.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > SZ.C &&
X/*
X *			    ACKNOWLEDGEMENTS
X *
X *	ZMDM was derived from rz/sz for Unix  posted by 
X *	Chuck Forsberg (...!tektronix!reed!omen!caf ). We
X *	thank him for his excellent code, and for giving
X *	us permission to use and distribute his code and
X *	documentation.
X *
X *	Atari St version by:
X *		Jwahar Bammi
X *			usenet: mandrill!bammi@{decvax,sun}.UUCP
X *			csnet:  bammi@mandrill.ces.CWRU.edu
X *			arpa:   bammi@mandrill.ces.CWRU.edu
X *			CompuServe: 71515,155
X */
X
X#include "config.h"
X#define SVERSION "sz 1.23 01-15-87"
X#define SSTVERSION "sz 1.01 03-07-87"
X#define OS	"Unix V7/BSD"
X
X#ifndef STANDALONE
X#define RETURN return
X#else
Xint bibi() {} /* dummy */
X#endif 
X
X/* #define SDEBUG */
X
X/*
X * sz.c By Chuck Forsberg
X *
X *	cc -O sz.c -o sz		USG (SYS III/V) Unix
X * 	cc -O -DV7  sz.c -o sz		Unix Version 7, 2.8 - 4.3 BSD
X *
X *		define CRCTABLE to use table driven CRC
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 *	St v 1.01
X *		added support for 32 bit CRC's (Zmodem) ++jrb
X *
X */
X
X#include "zmdm.h"
X#include "common.h"
X#include "zmodem.h"
X
X#ifndef Vsync 			/* Atari forgot these in osbind.h */
X#define Vsync()	xbios(37)
X#endif
X
X#ifndef Supexec
X		/* Some versions of osbind don't define Supexec */
X#define Supexec(X) xbios(38,X)
X#endif
X
X#define SLOGFILE "szlog"
X
X#define purgeline()	while(Bconstat(1)) Bconin(1)
X#define S_IFDIR 0x0010
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
X#if (MWC || MANX)
XFILE *fopen();
X#else
XFILE *fopen(), *fopenb();
X#endif
Xstatic unsigned long SaveIntr;
Xstatic int Resuming, ForceBin;
Xstatic int in;
X
X/* called by signal interrupt or terminate to clean things up */
Xbibis(n)
Xint n;
X{
X	canit(); flush_modem(); mode(0);
X	fprintf(STDERR, "\r\nsz: caught signal %d; exiting\n", n);
X
X	aexit(128+n);
X}
X
X/* Called when Zmodem gets an interrupt (^X) */
X#ifdef ONINTR
Xonintr()
X{
X	siggi = 0;
X	longjmp(intrjmp, -1);
X}
X#endif
X
X#define ZKER
Xint Zctlesc;	/* Encode control characters */
X
X#ifdef STANDALONE
Xint main(argc, argv)
X#else
Xint dosz(argc, argv)
X#endif
Xint argc;
Xchar **argv;
X{
X	register char *cp;
X	register int npats;
X	int agcnt; char **agcv;
X	char **patts;
X
X#ifdef STANDALONE
X#ifdef MWC
X	extern char *lmalloc();
X#endif
X
X	/* Set up Dta */
X	Fsetdta(&statbuf);
X
X	/* Get screen rez */
X	rez = Getrez();
X	drv_map = Drvmap();
X
X#if (MWC || MANX)
X#ifndef DYNABUF
X#ifdef MWC
X	if((bufr = (unsigned char *)lmalloc((unsigned long)BBUFSIZ))
X					 == (unsigned char *)NULL)
X#else
X	if((bufr = (unsigned char *)Malloc((unsigned long)BBUFSIZ))
X					 == (unsigned char *)NULL)
X#endif
X#else
X	if((bufr = dalloc()) == (unsigned char *)NULL)
X#endif /* DYNABUF */
X	{
X#ifdef REMOTE
X		Bauxws("Sorry, could not allocate enough memory\r\n");
X#else
X		Bconws("Sorry, could not allocate enough memory\r\n");
X#endif
X
X		Pterm(4);
X	}
X#else /* MWC || MANX */
X#ifdef DYNABUF
X	if((bufr = dalloc()) == (unsigned char *)NULL)
X	{
X#ifdef REMOTE
X		Bauxws("Sorry, could not allocate enough memory\r\n");
X#else
X		Bconws("Sorry, could not allocate enough memory\r\n");
X#endif
X		Pterm(5);
X	}
X#endif /* DYNABUF */
X#endif /* MWC || MANX */
X
X#ifndef REMOTE
X	STDERR = stderr;
X#else
X#ifndef DLIBS
X	if((STDERR = fopen("aux:", "rw")) == (FILE *)NULL)
X	{
X		Bauxws("Could not Open Aux Stream for Stderr\r\n");
X		finish();
X	}
X	setbuf(STDERR, (char *)NULL);
X#else
X	STDERR = stdaux;
X#endif /* DLIBS */
X	
X#endif /* REMOTE */
X	{
X		int speed;
X		speed = getbaud();
X		Baudrate = BAUD_RATE(speed);
X		SetIoBuf();
X		Rsconf(speed, 0,-1,-1,-1,-1);
X		Vsync(); Vsync();
X	}
X#endif /* STANDALONE */
X
X	SendType = 1;
X	Rxtimeout = 600;
X	npats=0;
X	if (argc<2)
X	{
X		susage();
X		RETURN(1);
X	}
X
X	initz();
X#ifndef STANDALONE
X	schkinvok(argv[0]);
X#else
X	Progname = "sz";
X#endif
X
X	SaveIntr = Setexc(0x0102, -1L);
X	BusErr   = Setexc(2, -1L);
X	AddrErr  = Setexc(3, -1L);
X
X	Verbose = 0;
X	Resuming = FALSE;
X	ForceBin = FALSE;
X	in = (-1);
X	vdebug = 0;
X
X#ifdef SDEBUG
X	logf = (FILE *)NULL;
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#ifdef CSTOPB
X				case '2':
X					Twostop = TRUE; break;
X#endif
X				case '7':
X					Wcsmask=0177; break;
X
X/*
X	On the St we look up the ext and decide. For Xmodem
X	transfers, the file is always sent in binary mode
X	and it is the responsibility of the receiver to
X	strip CR if so desired.
X				case 'a':
X					Lzconv = ZCNL;
X					Ascii = TRUE; break;
X				case 'b':
X					Lzconv = ZCBIN; break;
X*/
X
X/*  ST extention, force binary, useful to back up every thing
X *  in image mode, see -B option of rz too +jrb
X */
X				case 'B':
X					ForceBin = TRUE;
X					Lzconv = ZCBIN;
X					break;
X				case 'C':
X					if (--argc < 1) {
X						susage();
X						RETURN(1);
X					}
X					Cmdtries = atoi(*++argv);
X					break;
X				case 'i':
X					Cmdack1 = ZCACK1;
X					/* **** FALL THROUGH TO **** */
X				case 'c':
X					if (--argc != 1) {
X						susage();
X						RETURN(1);
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				case 'e':
X					Zctlesc = 1; break;
X				case 'k':
X					Blklen=KSIZE; break;
X				case 'L':
X					if (--argc < 1) {
X						susage();
X						RETURN(1);
X					}
X					blkopt = atoi(*++argv);
X					if (blkopt<32 || blkopt>1024)
X					{
X						susage();
X						RETURN(1);
X					}
X					break;
X				case 'l':
X					if (--argc < 1) {
X						susage();
X						RETURN(1);
X					}
X					Tframlen = atoi(*++argv);
X					if (Tframlen<32 || Tframlen>1024)
X					{
X						susage();
X						RETURN(1);
X					}
X					break;
X				case 'N':
X					Lzmanag = ZMDIFF;  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; Resuming = TRUE; break;
X				case 'q':
X					Quiet=TRUE; Verbose=0; break;
X				case 't':
X					if (--argc < 1) {
X						susage();
X						RETURN(1);
X					}
X					Rxtimeout = atoi(*++argv);
X					if (Rxtimeout<10 || Rxtimeout>1000)
X					{
X						susage();
X						RETURN(1);
X					}
X					break;
X#ifdef TESTATTN
X				case 'T':
X					Testattn = TRUE; break;
X#endif
X				case 'u':
X					++Unlinkafter; break;
X				case 'v':
X					++Verbose; break;
X				case 'X':
X					++Modem; break;
X				case 'y':
X					Lzmanag = ZMCLOB; break;
X				default:
X					susage();
X					RETURN(1);
X				}
X			}
X		}
X		else if ( !npats && argc>0) {
X			if (argv[0][0]) {
X				npats=argc;
X				patts=argv;
X			}
X		}
X	}
X	if (npats < 1 && !Command) 
X	{
X		susage();
X		RETURN(1);
X	}
X
X#ifdef SDEBUG
X	if (Verbose > 2)
X	{
X		if ((logf = fopen(SLOGFILE, "a"))== (FILE *)NULL)
X		{
X			fprintf(STDERR, "Can't open log file %s\n",SLOGFILE);
X			RETURN(0200);
X		}
X		fprintf(logf, "Progname=%s\n", Progname);
X		vdebug = 1;
X		fflush(logf);
X	}
X#endif
X
X	if ( !Quiet)
X	{
X		if (Verbose < 2)
X			Verbose = 2;
X	}
X
X
X	Setexc(0x0102, bibis);
X	Setexc(2, buserr);
X	Setexc(3, addrerr);
X
X	if(setjmp(busjmp))
X	{
X		/* On a bus error - instead of 2 bombs */
X		fprintf(STDERR,"\r\nFATAL: Bus Error\n\n");
X#ifdef SDEBUG
X		if(logf != (FILE *)NULL)
X			fclose(logf);
X#endif
X		if(in != -1)
X		{
X			stfclose(in);
X			in = (-1);
X		}
X		canit();
X		Setexc(2, BusErr);
X		Setexc(3, AddrErr);
X		Setexc(0x0102, SaveIntr);
X		RETURN(2);
X	}
X
X	if(setjmp(addrjmp))
X	{
X		/* On address error - instead of 3 bombs */
X		fprintf(STDERR,"\r\nFATAL: Address Error\n\n");
X#ifdef SDEBUG
X		if(logf != (FILE *)NULL)
X			fclose(logf);
X#endif
X		if(in != -1)
X		{
X			stfclose(in);
X			in = (-1);
X		}
X		canit();
X		Setexc(2, BusErr);
X		Setexc(3, AddrErr);
X		Setexc(0x0102, SaveIntr);
X		RETURN(3);
X	}
X
X	if((Exitcode = setjmp(abrtjmp)))
X	{
X		fprintf(STDERR,"\nTransfer ABORT\n\n");
X#ifdef SDEBUG
X	if(logf != (FILE *)NULL)
X		fclose(logf);
X#endif
X		if(in != -1)
X		{
X			stfclose(in);
X			in = (-1);
X		}
X		Setexc(2, BusErr);
X		Setexc(3, AddrErr);
X		Setexc(0x0102, SaveIntr);
X		RETURN(Exitcode);
X	}
X
X	mode(1);
X
X
X	if ( !Modem) {
X		if (!Command && !Quiet && Verbose != 1)
X		{
X			fprintf(STDERR, "sz: %d file%s requested:\n",
X				npats, npats>1?"s":"");
X			for ( agcnt=npats, agcv=patts; --agcnt>=0; )
X			{
X				fprintf(STDERR, "%s ", *agcv++);
X			}
X			fprintf(STDERR, "\n\n");
X
X#ifdef SDEBUG
X			if(Verbose > 2)
X			{
X				fprintf(logf, "sz: %d file%s requested:\n",
X					npats, npats>1?"s":"");
X				for ( agcnt=npats, agcv=patts; --agcnt>=0; )
X				{
X					fprintf(logf, "%s ", *agcv++);
X				}
X				fprintf(logf, "\n");
X				fflush(logf);
X			}
X#endif
X		}
X		if (!Nozmodem) {
X			stohdr(0L);
X			if (Command)
X				Txhdr[ZF0] = ZCOMMAND;
X			zshhdr(ZRQINIT, Txhdr);
X		}
X	}
X	flush_modem();
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	flush_modem();
X	mode(0);
X
X#ifdef SDEBUG
X	if(logf != (FILE *)NULL)
X		fclose(logf);
X#endif
X	if(in != -1)
X	{
X		fclose(in);
X		in = (-1);
X	}
X
X	putc('\n', STDERR);
X	Setexc(2, BusErr);
X	Setexc(3, AddrErr);
X	Setexc(0x0102, SaveIntr);
X	RETURN((errcnt != 0) | Exitcode);
X
X}
X
X#ifdef STANDALONE
XRETURN(n)
Xint n;
X{
X	ResetIoBuf();
X#if (MWC || MANX)
X#ifndef DYNABUF
X	free(bufr);
X#else
X	Mfree(bufr);
X#endif
X#else
X#ifdef DYNABUF
X	Mfree(bufr);
X#endif
X#endif
X	exit(n);
X}
X#endif /* STANDALONE */
X
Xwcsend(argc, argp)
Xchar *argp[];
X{
X	register int n;
X
X	Crcflg=FALSE;
X	Firstsec=TRUE;
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 (getzrxinit()) {
X				Exitcode=0200; canit();
X			}
X			else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
X				Exitcode=0200; canit();
X			}
X			Exitcode = 1; return OK;
X		}
X		canit();
X		fprintf(STDERR,"\n\nCan't open any requested files.\n\n");
X		return ERROR;
X	}
X	if (Zmodem)
X		saybibi();
X	else
X		wctxpn("");
X	return OK;
X}
X
Xwcs(oname)
Xchar *oname;
X{
X	extern struct stat statbuf;
X	char name[PATHLEN];
X
X	strcpy(name, oname);
X	++Noeofseen;  Lastread = 0;  Lastc = (-1); Dontread = FALSE;
X
X	/* Check for directory or block special files */
X	if(Fsfirst(name,(int)(0x01 | 0x010 | 0x020)) != 0)
X	{
X		++errcnt;
X		return OK;	/* may be others */
X	}
X
X	if (statbuf.st_mode & S_IFDIR ) {
X		return OK;
X	}
X
X	if((in = stfopen(oname,"r")) <= 0){
X		++errcnt;
X		return OK;	/* pass over it, there may be others */
X	}
X
X	++Filcnt;
X	switch (wctxpn(name)) {
X	case ERROR:
X		return ERROR;
X	case ZSKIP:
X		return OK;
X	}
X	if (!Zmodem && wctx()==ERROR)
X		return ERROR;
X	if (Unlinkafter)
X		unlink(oname);
X	return 0;
X}
X
X#define ISDRIVE(X) ( (((X >= 'a') && (X <= 'n'))) || ((X >= 'A') && (X <= 'N')))
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 St's Fsfirst() 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	unsigned long unixtime;
X	extern struct stat statbuf;
X	extern unsigned long st2unix();	/* Convert St's date and time to unix
X				   time (seconds since Jan 1 1970 00:00:00) */
X
X	if(*name)
X		if(Fsfirst(name,(int)(0x01 | 0x020)) != 0)
X			return ERROR;
X
X	if (Modem) {
X#ifndef REMOTE
X		if (*name) {
X			fprintf(STDERR,
X			"Outgoing:\n\t Name: %s\n\t Size: %ld Bytes\n\
X\tBlocks: %ld\n\tBufSize: %ld\n\n",
X			  name, statbuf.st_size, statbuf.st_size>>7, (long)BBUFSIZ);
X		}
X#endif /* REMOTE */
X		return OK;
X	}
X
X	vfile2("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
X
X	if ( !Zmodem)
X		if (getnak())
X			return ERROR;
X
X	/* convert to Unix style path names */
X	/* skip any device identifier */
X	if(ISDRIVE(name[0]) && (name[1] == ':'))
X		name = &name[2];
X
X	for(p = name; *p != '\0'; p++)
X	{
X		if(*p == '\\')
X			*p = '/';
X	}
X
X	if(!Resuming)
X	{
X		if(ForceBin)
X		{
X			Lzconv = ZCBIN;
X			Ascii = FALSE;
X		}
X		else
X		{
X			if(!isbinary(name))
X			{
X				/* We indicate to the other side */
X				Lzconv = ZCNL;
X				Ascii = TRUE;
X			}
X			else
X			{
X				Lzconv = ZCBIN;
X				Ascii = FALSE;
X			}
X		}
X	}
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	for (p=name, q=secbuf ; *p; )
X		if ((*q++ = *p++) == '/' && !Fullname)
X			q = secbuf;
X	*q++ = 0;
X	p=q;
X	while (q < (secbuf + KSIZE))
X		*q++ = 0;
X	if (*name)
X	{
X		unixtime = st2unix(statbuf.st_time, statbuf.st_date);
X		sprintf(p, "%lu %lo %o", statbuf.st_size,
X			unixtime,
X			 ((statbuf.st_mode & 0x01)?0444:0644));
X	}
X
X	if(Verbose)
X#ifndef REMOTE
X		fprintf(STDERR,
X"Outgoing: [Hit CTRL-C to Cancel]\n\tName: %s\n\tSize: %ld Bytes\n\tBufSize:\
X %ld\n",
X			name, statbuf.st_size, (long)BBUFSIZ);
X	if(!Resuming)
X	{
X		fprintf(STDERR,"\tMode: %s\n\n", (Ascii)?"ASCII":"BINARY");
X	}
X	else
X	{
X		fprintf(STDERR,"\tMode: Resume Transfer Mode\n\n");
X	}
X#endif
X
X#ifdef SDEBUG
X	if(Verbose > 2)
X	{
X		fprintf(STDERR,"File: %s (%s)\n", name, p);
X		fprintf(logf,"File: %s (%s)\n", name, p);
X		fflush(logf);
X	}
X#endif
X
X	/* force 1k blocks if name won't fit in 128 byte block */
X	if (secbuf[125])
X		Blklen=KSIZE;
X	else {		/* A little goodie for IMP/KMD */
X		if (Zmodem)
X			Blklen = SECSIZ;
X		secbuf[127] = (statbuf.st_size + 127) >>7;
X		secbuf[126] = (statbuf.st_size + 127) >>15;
X	}
X	if (Zmodem)
X		return zsendfile(secbuf, (int)(1+strlen(p)+ 
X				(int)((long)p-(long)secbuf)), statbuf.st_size);
X	if (wcputsec(secbuf, 0, SECSIZ)==ERROR)
X		return ERROR;
X	return OK;
X}
X
Xgetnak()
X{
X	register int firstch;
X
X	Lastrx = 0;
X	for (;;) {
X		switch (firstch = readock(800,1)) {
X		case ZPAD:
X			if (getzrxinit())
X				return ERROR;
X			Ascii = 0;
X			return FALSE;
X		case TIMEOUT:
X			vfile("Timeout on pathname\n");
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()
X{
X	register int sectnum, attempts, firstch;
X
X	Firstsec=TRUE;
X
X	while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC
X	  && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
X		;
X	if (firstch==CAN) {
X		fprintf(STDERR, "\r\nReceiver CANcelled\n");
X		return ERROR;
X	}
X	if (firstch==WANTCRC)
X		Crcflg=TRUE;
X	if (firstch==WANTG)
X		Crcflg=TRUE;
X	sectnum=1;
X	while (filbuf(secbuf, Blklen)) {
X		if (wcputsec(secbuf, sectnum, Blklen)==ERROR) {
X			return ERROR;
X		} else
X			sectnum++;
X	}
X
X#ifndef REMOTE
X	if (Verbose>1)
X	{
X		fprintf(STDERR, "\nClosing\n\n");
X#ifdef SDEBUG
X		if(Verbose > 2)
X		{
X			fprintf(logf, " Closing\n");
X			fflush(logf);
X		}
X#endif
X	}
X#endif /* REMOTE */
X
X	stfclose(in);
X	in = (-1);
X
X	attempts=0;
X	do {
X		vfile(" EOT ");
X		purgeline();
X		sendline(EOT);
X		flush_modem();
X		++attempts;
X	}
X		while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX);
X	if (attempts == RETRYMAX) {
X		fprintf(STDERR, "\r\nNo ACK on EOT\n");
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 int checksum, wcj;
X	register char *cp;
X	unsigned int oldcrc;
X	int firstch;
X	int attempts;
X
X	firstch=0;	/* part of logic to detect CAN CAN */
X
X#ifndef REMOTE
X	if (Verbose>1)
X	{
X		fprintf(STDERR, "\rBlock %06d  %04dK ", Totsecs, (Totsecs>>3));
X#ifdef SDEBUG
X		if(Verbose > 2)
X		{
X			fprintf(logf, "\rBlock %d %dK ", Totsecs, (Totsecs>>3) );
X			fflush(logf);
X		}
X#endif
X	}
X#endif /* REMOTE */
X
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
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				fprintf(STDERR, "\r\nCancelled\n");  return ERROR;
X			}
X			break;
X		case TIMEOUT:
X			vfile("Timeout on sector ACK\n"); continue;
X		case WANTCRC:
X			if (Firstsec)
X				Crcflg = TRUE;
X		case NAK:
X			vfile("NAK on sector\n"); continue;
X		case ACK: 
X			Firstsec=FALSE;
X			Totsecs += (cseclen>>7);
X			return OK;
X		case ERROR:
X			vfile("Got burst for sector ACK\n"); break;
X		default:
X			vfile("Got %02x for sector ACK\n", 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	fprintf(STDERR, "\r\nRetry Count Exceeded\n");
X	return ERROR;
X}
X
X/* fill buf with count chars padding with ^Z for CPM */
Xfilbuf(buf, count)
Xregister unsigned char *buf;
Xregister int count;
X{
X	register int m;
X
X	if((buf[0] = stgetc(in)) == EOF)
X		return 0;
X
X	for(m = 1; (m < count) && ((buf[m] = stgetc(in)) != EOF); m++)
X		/* loop */ ;
X
X	while (m < count)
X		buf[m++] = 032;
X
X	return count;
X
X}
X/* fill buf with count chars */
Xzfilbuf(buf, count)
Xregister char *buf;
X{
X	register int c, m;
X
X	m=count;
X	while ((c=stgetc(in))!=EOF) {
X		*buf++ =c;
X		if (--m == 0)
X			break;
X	}
X	return (count - m);
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)
Xint 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	if (setjmp(tohere)) {
X		vfile("TIMEOUT\n");
X		return TIMEOUT;
X	}
X	c = timeout >> 3;
X	if (c<2)
X		c=2;
X#ifdef SDEBUG
X	if (Verbose>3) {
X		fprintf(STDERR, "Timeout=%d Calling alarm(%d) ", timeout, c);
X		byt[1] = 0;
X		fprintf(logf, "Timeout=%d Calling alarm(%d) ", timeout, c);
SHAR_EOF
echo "End of part 4"
echo "File SZ.C is continued in part 5"
echo "5" > s2_seq_.tmp
exit 0