[comp.binaries.ibm.pc] Zmodem for Unix and VAX/VMS, part 2of4

w8sdz@brl-smoke.ARPA (Keith B. Petersen ) (04/28/88)

---- Cut Here and unpack ----
#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file rz.1 continued
#
CurArch=2
if test ! -r ._seq_
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
) < ._seq_ || exit 1
echo "x - Continuing file rz.1"
sed 's/^X//' << 'SHAR_EOF' >> rz.1
XCPU utilization.
X
XThe VMS version causes DCL to generate a random off the wall
Xerror message under some error conditions; this is a result of
Xthe incompatibility of the VMS "exit" function with the
XUnix/MSDOS standard.
X.SH "ZMODEM CAPABILITIES"
X.I Rz
Xsupports incoming ZMODEM binary (-b), ASCII (-a),
Xprotect (-p),
Xclobber (-y),
Xand append (-+)
Xrequests.
XThe default is protect (-p) and binary (-b).
X
XThe Unix versions support ZMODEM command execution.
X.SH FILES
Xrz.c, crctab.c, rbsb.c, zm.c, zmodem.h Unix source files.
X
Xrz.c, crctab.c, vrzsz.c, zm.c, zmodem.h, vmodem.h, vvmodem.c,
XVMS source files.
X
X/tmp/rzlog stores debugging output generated with -vv option
X(rzlog on VMS).
SHAR_EOF
echo "File rz.1 is complete"
chmod 0644 rz.1 || echo "restore of rz.1 fails"
fi
if test -f rz.c; then echo "File rz.c exists"; else
echo "x - extracting rz.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rz.c &&
X#define VERSION "2.02 04-22-88"
X#define PUBDIR "/usr/spool/uucppublic"
X
X/*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz;
X<-xtx-*> cc386 -Ox -DMD -DSEGMENTS=8 rz.c -o $B/rz;  size $B/rz
X *
X * rz.c By Chuck Forsberg
X *
X *	cc -O rz.c -o rz		USG (3.0) Unix
X * 	cc -O -DV7  rz.c -o rz		Unix V7, BSD 2.8 - 4.3
X *
X *	ln rz rb;  ln rz rx			For either system
X *
X *	ln rz /usr/bin/rzrmail		For remote mail.  Make this the
X *					login shell. rzrmail then calls
X *					rmail(1) to deliver mail.
X *
X * To compile on VMS:
X *
X *	define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
X *	cc rz.c
X *	cc vvmodem.c
X *	link rz,vvmodem
X *	rz :== $disk:[username.subdir]rz.exe
X *
X *
X *  Unix is a trademark of Western Electric Company
X *
X * A program for Unix to receive files and commands from computers running
X *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
X *  rz uses Unix buffered input to reduce wasted CPU time.
X *
X * Iff the program is invoked by rzCOMMAND, output is piped to 
X * "COMMAND filename"  (Unix only)
X *
X *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
X *  read(2) the same way as Unix. ONEREAD must be defined to force one
X *  character reads for these systems. Added 7-01-84 CAF
X *
X *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
X *
X *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
X *  Byte Information Exchange.
X *
X *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
X *  doesn't work properly (even though it compiles without error!),
X *
X *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
X *    for CP/M-80 systems that cannot overlap modem and disk I/O.
X *
X *  VMS flavor hacks begin with rz version 2.00
X *
X *  -DMD may be added to compiler command line to compile in
X *    Directory-creating routines from Public Domain TAR by John Gilmore
X *
X *  HOWMANY may be tuned for best performance
X *
X *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
X */
X
X#ifdef vax11c
X#include <types.h>
X#include <stat.h>
X#define LOGFILE "rzlog.tmp"
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include <errno.h>
X#define OS "VMS"
X#define BUFREAD
Xextern int errno;
X#define SS_NORMAL SS$_NORMAL
X#else
X#define SS_NORMAL 0
X#define LOGFILE "/tmp/rzlog"
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include <errno.h>
Xextern int errno;
XFILE *popen();
X#endif
X
X#define OK 0
X#define FALSE 0
X#define TRUE 1
X#define ERROR (-1)
X
X/*
X * Max value for HOWMANY is 255.
X *   A larger value reduces system overhead but may evoke kernel bugs.
X *   133 corresponds to an XMODEM/CRC sector
X */
X#ifndef HOWMANY
X#define HOWMANY 133
X#endif
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 TIMEOUT (-2)
X#define RCDO (-3)
X#define ERRORMAX 5
X#define RETRYMAX 5
X#define WCEOT (-10)
X#define PATHLEN 257	/* ready for 4.2 bsd ? */
X#define UNIXFILE 0xF000	/* The S_IFMT file mask bit for stat */
X
Xint Zmodem=0;		/* ZMODEM protocol requested */
Xint Nozmodem = 0;	/* If invoked as "rb" */
Xunsigned Baudrate = 2400;
X#ifdef vax11c
X#include "vrzsz.c"	/* most of the system dependent stuff here */
X#else
X#include "rbsb.c"	/* most of the system dependent stuff here */
X#endif
X#include "crctab.c"
X
Xchar *substr();
XFILE *fout;
X
X/*
X * Routine to calculate the free bytes on the current file system
X *  ~0 means many free bytes (unknown)
X */
Xlong getfree()
X{
X	return(~0L);	/* many free bytes ... */
X}
X
Xint Lastrx;
Xint Crcflg;
Xint Firstsec;
Xint Eofseen;		/* indicates cpm eof (^Z) has been received */
Xint errors;
Xint Restricted=0;	/* restricted; no /.. or ../ in filenames */
X#ifdef ONEREAD
X/* Sorry, Regulus and some others don't work right in raw mode! */
Xint Readnum = 1;	/* Number of bytes to ask for in read() from modem */
X#else
Xint Readnum = HOWMANY;	/* Number of bytes to ask for in read() from modem */
X#endif
X
X#define DEFBYTL 2000000000L	/* default rx file size */
Xlong Bytesleft;		/* number of bytes of incoming file left */
Xlong Modtime;		/* Unix style mod time for incoming file */
Xint Filemode;		/* Unix style mode for incoming file */
Xchar Pathname[PATHLEN];
Xchar *Progname;		/* the name by which we were called */
X
Xint Batch=0;
Xint Topipe=0;
Xint MakeLCPathname=TRUE;	/* make received pathname lower case */
Xint Verbose=0;
Xint Quiet=0;		/* overrides logic that would otherwise set verbose */
Xint Nflag = 0;		/* Don't really transfer files */
Xint Rxclob=FALSE;	/* Clobber existing file */
Xint Rxbinary=FALSE;	/* receive all files in bin mode */
Xint Rxascii=FALSE;	/* receive files in ascii (translate) mode */
Xint Thisbinary;		/* current file is to be received in bin mode */
Xint Blklen;		/* record length of received packets */
X
X#ifdef SEGMENTS
Xint chinseg = 0;	/* Number of characters received in this data seg */
Xchar secbuf[1+(SEGMENTS+1)*1024];
X#else
Xchar secbuf[1025];
X#endif
X
X
Xchar linbuf[HOWMANY];
Xint Lleft=0;		/* number of characters in linbuf */
Xtime_t timep[2];
Xchar Lzmanag;		/* Local file management request */
Xchar zconv;		/* ZMODEM file conversion request */
Xchar zmanag;		/* ZMODEM file management request */
Xchar ztrans;		/* ZMODEM file transport request */
Xint Zctlesc;		/* Encode control characters */
Xint Zrwindow = 1400;	/* RX window size (controls garbage count) */
X
Xjmp_buf tohere;		/* For the interrupt on RX timeout */
X
X#define xsendline(c) sendline(c)
X#include "zm.c"
X
Xint tryzhdrtype=ZRINIT;	/* Header type to send corresponding to Last rx close */
X
Xalrm()
X{
X	longjmp(tohere, -1);
X}
X
X/* called by signal interrupt or terminate to clean things up */
Xbibi(n)
X{
X	if (Zmodem)
X		zmputs(Attn);
X	canit(); mode(0);
X	fprintf(stderr, "rz: caught signal %d; exiting", n);
X	cucheck();
X	exit(128+n);
X}
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	register char *cp;
X	register npats;
X	char *virgin, **patts;
X	char *getenv();
X	int exitcode;
X
X	Rxtimeout = 100;
X	setbuf(stderr, NULL);
X	if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
X		Restricted=TRUE;
X
X	from_cu();
X#ifdef vax11c
X	Progname = virgin = "rz";
X#else
X	chkinvok(virgin=argv[0]);	/* if called as [-]rzCOMMAND set flag */
X#endif
X	npats = 0;
X	while (--argc) {
X		cp = *++argv;
X		if (*cp == '-') {
X			while( *++cp) {
X				switch(*cp) {
X				case '\\':
X					 cp[1] = toupper(cp[1]);  continue;
X				case '+':
X					Lzmanag = ZMAPND; break;
X				case 'a':
X					Rxascii=TRUE;  break;
X				case 'b':
X					Rxbinary=TRUE; break;
X				case 'c':
X					Crcflg=TRUE; break;
X#ifndef vax11c
X				case 'D':
X					Nflag = TRUE; break;
X#endif
X				case 'e':
X					Zctlesc = 1; break;
X				case 'p':
X					Lzmanag = ZMPROT;  break;
X				case 'q':
X					Quiet=TRUE; Verbose=0; break;
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 'w':
X					if (--argc < 1) {
X						usage();
X					}
X					Zrwindow = atoi(*++argv);
X					break;
X				case 'u':
X					MakeLCPathname=FALSE; break;
X				case 'v':
X					++Verbose; break;
X				case 'y':
X					Rxclob=TRUE; 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			}
X		}
X	}
X	if (npats > 1)
X		usage();
X	if (Batch && npats)
X		usage();
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		fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
X	}
X	if (Fromcu && !Quiet) {
X		if (Verbose == 0)
X			Verbose = 2;
X	}
X	mode(1);
X	if (signal(SIGINT, bibi) == SIG_IGN) {
X		signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
X	}
X	else {
X		signal(SIGINT, bibi); signal(SIGKILL, bibi);
X	}
X	signal(SIGTERM, bibi);
X	if (wcreceive(npats, patts)==ERROR) {
X		exitcode=0200;
X		canit();
X	}
X	mode(0);
X	if (exitcode && !Zmodem)	/* bellow again with all thy might. */
X		canit();
X	if (exitcode)
X		cucheck();
X	exit(exitcode ? exitcode:SS_NORMAL);
X}
X
X
Xusage()
X{
X	cucheck();
X#ifdef vax11c
X	fprintf(stderr,"Usage:	rz [-abeuvy]\n");
X#else
X	fprintf(stderr,"Usage:	rz [-abeuvy]		(ZMODEM)\n");
X	fprintf(stderr,"or	rb [-abuvy]		(YMODEM)\n");
X	fprintf(stderr,"or	rx [-abcv] file	(XMODEM or XMODEM-1k)\n");
X#endif
X	fprintf(stderr,"	  -a ASCII transfer (strip CR)\n");
X	fprintf(stderr,"	  -b Binary transfer for all files\n");
X#ifndef vax11c
X	fprintf(stderr,"	  -c Use 16 bit CRC	(XMODEM)\n");
X#endif
X	fprintf(stderr,"	  -e Escape control characters	(ZMODEM)\n");
X	fprintf(stderr,"	  -v Verbose more v's give more info\n");
X	fprintf(stderr,"	  -y Yes, clobber existing file if any\n");
X	fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
X	  Progname, VERSION, OS);
X	fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
X	exit(SS_NORMAL);
X}
X/*
X *  Debugging information output interface routine
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/*
X * Let's receive something already.
X */
X
Xchar *rbmsg =
X"%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
X
Xwcreceive(argc, argp)
Xchar **argp;
X{
X	register c;
X
X	if (Batch || argc==0) {
X		Crcflg=1;
X		if ( !Quiet)
X			fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
X		if (c=tryz()) {
X			if (c == ZCOMPL)
X				return OK;
X			if (c == ERROR)
X				goto fubar;
X			c = rzfiles();
X			if (c)
X				goto fubar;
X		} else {
X			for (;;) {
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	} else {
X		Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
X
X		procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
X		fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
X		if ((fout=fopen(Pathname, "w")) == NULL)
X			return ERROR;
X		if (wcrx()==ERROR)
X			goto fubar;
X	}
X	return OK;
Xfubar:
X	canit();
X#ifndef vax11c
X	if (Topipe && fout) {
X		pclose(fout);  return ERROR;
X	}
X#endif
X	if (fout)
X		fclose(fout);
X#ifndef vax11c
X	if (Restricted) {
X		unlink(Pathname);
X		fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
X	}
X#endif
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 c;
X
X#ifdef NFGVMIN
X	readline(1);
X#else
X	purgeline();
X#endif
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		if (c == WCEOT) {
X			zperr( "Pathname fetch returned %d", c);
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	register char *p;
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		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 &0377)) {
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&0377)) {
X			zperr( "Received dup Sector");
X			sendchar=ACK;
X		}
X		else if (sectcurr==WCEOT) {
X			if (closeit())
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			zperr( "Sync Error");
X			return ERROR;
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 */
X
Xwcgetsec(rxbuf, maxtime)
Xchar *rxbuf;
Xint maxtime;
X{
X	register checksum, wcj, firstch;
X	register unsigned short oldcrc;
X	register char *p;
X	int sectcurr;
X
X	for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
X
X		if ((firstch=readline(maxtime))==STX) {
X			Blklen=1024; goto get2;
X		}
X		if (firstch==SOH) {
X			Blklen=128;
Xget2:
X			sectcurr=readline(1);
X			if ((sectcurr+(oldcrc=readline(1)))==0377) {
X				oldcrc=checksum=0;
X				for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
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					oldcrc=updcrc(firstch, oldcrc);
X					if ((firstch=readline(1)) < 0)
X						goto bilge;
X					oldcrc=updcrc(firstch, oldcrc);
X					if (oldcrc & 0xFFFF)
X						zperr( "CRC");
X					else {
X						Firstsec=FALSE;
X						return sectcurr;
X					}
X				}
X				else if (((checksum-firstch)&0377)==0) {
X					Firstsec=FALSE;
X					return sectcurr;
X				}
X				else
X					zperr( "Checksum");
X			}
X			else
X				zperr("Sector number garbled");
X		}
X		/* make sure eot really is eot and not just mixmash */
X#ifdef NFGVMIN
X		else if (firstch==EOT && readline(1)==TIMEOUT)
X			return WCEOT;
X#else
X		else if (firstch==EOT && Lleft==0)
X			return WCEOT;
X#endif
X		else if (firstch==CAN) {
X			if (Lastrx==CAN) {
X				zperr( "Sender CANcelled");
X				return ERROR;
X			} else {
X				Lastrx=CAN;
X				continue;
X			}
X		}
X		else if (firstch==TIMEOUT) {
X			if (Firstsec)
X				goto humbug;
Xbilge:
X			zperr( "TIMEOUT");
X		}
X		else
X			zperr( "Got 0%o sector header", firstch);
X
Xhumbug:
X		Lastrx=0;
X		while(readline(1)!=TIMEOUT)
X			;
X		if (Firstsec) {
X			sendline(Crcflg?WANTCRC:NAK);
X			Lleft=0;	/* Do read next time ... */
X		} else {
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#ifndef vax11c
X/*
X * This version of readline is reasoably well suited for
X * reading many characters.
X *  (except, currently, for the Regulus version!)
X *
X * timeout is in tenths of seconds
X */
Xreadline(timeout)
Xint timeout;
X{
X	register n;
X	static char *cdq;	/* pointer for removing chars from linbuf */
X
X	if (--Lleft >= 0) {
X		if (Verbose > 8) {
X			fprintf(stderr, "%02x ", *cdq&0377);
X		}
X		return (*cdq++ & 0377);
X	}
X	n = timeout/10;
X	if (n < 2)
X		n = 3;
X	if (Verbose > 5)
X		fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
X		  n, Readnum);
X	if (setjmp(tohere)) {
X#ifdef TIOCFLUSH
X/*		ioctl(iofd, TIOCFLUSH, 0); */
X#endif
X		Lleft = 0;
X		if (Verbose>1)
X			fprintf(stderr, "Readline:TIMEOUT\n");
X		return TIMEOUT;
X	}
X	signal(SIGALRM, alrm); alarm(n);
X	Lleft=read(iofd, cdq=linbuf, Readnum);
X	alarm(0);
X	if (Verbose > 5) {
X		fprintf(stderr, "Read returned %d bytes\n", Lleft);
X	}
X	if (Lleft < 1)
X		return TIMEOUT;
X	--Lleft;
X	if (Verbose > 8) {
X		fprintf(stderr, "%02x ", *cdq&0377);
X	}
X	return (*cdq++ & 0377);
X}
X
X
X
X/*
X * Purge the modem input queue of all characters
X */
Xpurgeline()
X{
X	Lleft = 0;
X#ifdef USG
X	ioctl(iofd, TCFLSH, 0);
X#else
X	lseek(iofd, 0L, 2);
X#endif
X}
X#endif
X
X
X/*
X * Process incoming file information header
X */
Xprocheader(name)
Xchar *name;
X{
X	register char *openmode, *p, **pp;
X
X	/* set default parameters and overrides */
X	openmode = "w";
X	Thisbinary = (!Rxascii) || Rxbinary;
X	if (Lzmanag)
X		zmanag = Lzmanag;
X
X	/*
X	 *  Process ZMODEM remote file management requests
X	 */
X	if (!Rxbinary && zconv == ZCNL)	/* Remote ASCII override */
X		Thisbinary = 0;
X	if (zconv == ZCBIN)	/* Remote Binary override */
X		Thisbinary = TRUE;
X	else if (zmanag == ZMAPND)
X		openmode = "a";
X
X#ifndef BIX
X	/* Check for existing file */
X	if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
X		fclose(fout);  return ERROR;
X	}
X#endif
X
X	Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
X
X	p = name + 1 + strlen(name);
X	if (*p) {	/* file coming from Unix or DOS system */
X		sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
X#ifndef vax11c
X		if (Filemode & UNIXFILE)
X			++Thisbinary;
X#endif
X		if (Verbose) {
X			fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
X			  name, Bytesleft, Modtime, Filemode);
X		}
X	}
X
X#ifdef BIX
X	if ((fout=fopen("scratchpad", openmode)) == NULL)
X		return ERROR;
X	return OK;
X#else
X
X	else {		/* 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#ifndef vax11c
X	if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
X	  && !(Filemode&UNIXFILE))
X		uncaps(name);
X#endif
X	if (Topipe) {
X		sprintf(Pathname, "%s %s", Progname+2, name);
X		if (Verbose)
X			fprintf(stderr,  "Topipe: %s %s\n",
X			  Pathname, Thisbinary?"BIN":"ASCII");
X#ifndef vax11c
X		if ((fout=popen(Pathname, "w")) == NULL)
X			return ERROR;
X#endif
X	} else {
X		strcpy(Pathname, name);
X		if (Verbose) {
X			fprintf(stderr,  "Receiving %s %s %s\n",
X			  name, Thisbinary?"BIN":"ASCII", openmode);
X		}
X		checkpath(name);
X		if (Nflag)
X			name = "/dev/null";
X#ifdef MD
X		fout = fopen(name, openmode);
X		if ( !fout)
X			if (make_dirs(name))
X				fout = fopen(name, openmode);
X#else
X		fout = fopen(name, openmode);
X#endif
X		if ( !fout)
X			return ERROR;
X	}
X	return OK;
X#endif /* BIX */
X}
X
X#ifdef MD
X/*
X *  Directory-creating routines from Public Domain TAR by John Gilmore
X */
X
X/*
X * After a file/link/symlink/dir creation has failed, see if
X * it's because some required directory was not present, and if
X * so, create all required dirs.
X */
Xmake_dirs(pathname)
Xregister char *pathname;
X{
X	register char *p;		/* Points into path */
X	int madeone = 0;		/* Did we do anything yet? */
X	int save_errno = errno;		/* Remember caller's errno */
X
X	if (errno != ENOENT)
X		return 0;		/* Not our problem */
X
X	for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
X		/* Avoid mkdir of empty string, if leading or double '/' */
X		if (p == pathname || p[-1] == '/')
X			continue;
X		/* Avoid mkdir where last part of path is '.' */
X		if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
X			continue;
X		*p = 0;				/* Truncate the path there */
X		if ( !mkdir(pathname, 0777)) {	/* Try to create it as a dir */
X			vfile("Made directory %s\n", pathname);
X			madeone++;		/* Remember if we made one */
X			*p = '/';
X			continue;
X		}
X		*p = '/';
X		if (errno == EEXIST)		/* Directory already exists */
X			continue;
X		/*
X		 * Some other error in the mkdir.  We return to the caller.
X		 */
X		break;
X	}
X	errno = save_errno;		/* Restore caller's errno */
X	return madeone;			/* Tell them to retry if we made one */
X}
X
X#if (MD != 2)
X#define	TERM_SIGNAL(status)	((status) & 0x7F)
X#define TERM_COREDUMP(status)	(((status) & 0x80) != 0)
X#define TERM_VALUE(status)	((status) >> 8)
X/*
X * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
X */
Xmkdir(dpath, dmode)
Xchar *dpath;
Xint dmode;
X{
X	int cpid, status;
X	struct stat statbuf;
X
X	if (stat(dpath,&statbuf) == 0) {
X		errno = EEXIST;		/* Stat worked, so it already exists */
X		return -1;
X	}
X
X	/* If stat fails for a reason other than non-existence, return error */
X	if (errno != ENOENT) return -1; 
X
X	switch (cpid = fork()) {
X
X	case -1:			/* Error in fork() */
X		return(-1);		/* Errno is set already */
X
X	case 0:				/* Child process */
X		/*
X		 * Cheap hack to set mode of new directory.  Since this
X		 * child process is going away anyway, we zap its umask.
X		 * FIXME, this won't suffice to set SUID, SGID, etc. on this
X		 * directory.  Does anybody care?
X		 */
X		status = umask(0);	/* Get current umask */
X		status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
X		execl("/bin/mkdir", "mkdir", dpath, (char *)0);
X		_exit(-1);		/* Can't exec /bin/mkdir */
X	
X	default:			/* Parent process */
X		while (cpid != wait(&status)) ;	/* Wait for kid to finish */
X	}
X
X	if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
X		errno = EIO;		/* We don't know why, but */
X		return -1;		/* /bin/mkdir failed */
X	}
X
X	return 0;
X}
X#endif /* MD != 2 */
X#endif /* MD */
X
X/*
X * Putsec writes the n characters of buf to receive file fout.
X *  If not in binary mode, carriage returns, and all characters
X *  starting with CPMEOF are discarded.
X */
Xputsec(buf, n)
Xchar *buf;
Xregister n;
X{
X	register char *p;
X
X	if (n == 0)
X		return OK;
X	if (Thisbinary) {
X		for (p=buf; --n>=0; )
X			putc( *p++, fout);
X	}
X	else {
X		if (Eofseen)
X			return OK;
X		for (p=buf; --n>=0; ++p ) {
X			if ( *p == '\r')
X				continue;
X			if (*p == CPMEOF) {
X				Eofseen=TRUE; return OK;
X			}
X			putc(*p ,fout);
X		}
X	}
X	return OK;
X}
X
X#ifndef vax11c
X/*
X *  Send a character to modem.  Small is beautiful.
X */
Xsendline(c)
X{
X	char d;
X
X	d = c;
X	if (Verbose>6)
X		fprintf(stderr, "Sendline: %x\n", c);
X	write(1, &d, 1);
X}
X
Xflushmo() {}
X#endif
X
X
X
X
X
X/* make string s lower case */
Xuncaps(s)
Xregister char *s;
X{
X	for ( ; *s; ++s)
X		if (isupper(*s))
X			*s = tolower(*s);
X}
X/*
X * IsAnyLower returns TRUE if string s has lower case letters.
X */
XIsAnyLower(s)
Xregister char *s;
X{
X	for ( ; *s; ++s)
X		if (islower(*s))
X			return TRUE;
X	return FALSE;
X}
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
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, "Retry %d: ", errors);
X	fprintf(stderr, s, p, u);
X	fprintf(stderr, "\n");
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#ifdef vax11c
X	raw_wbuf(strlen(canistr), canistr);
X	purgeline();
X#else
X	printf(canistr);
X	Lleft=0;	/* Do read next time ... */
X	fflush(stdout);
X#endif
X}
X
X
Xreport(sct)
Xint sct;
X{
X	if (Verbose>1)
X		fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
X}
X
X#ifndef vax11c
X/*
X * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
X * If called as [-][dir/../]rzCOMMAND set the pipe flag
X * If called as rb 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]=='r' && s[1]=='z')
X		Batch = TRUE;
X	if (s[0]=='r' && s[1]=='b')
X		Batch = Nozmodem = TRUE;
X	if (s[2] && s[0]=='r' && s[1]=='b')
X		Topipe=TRUE;
X	if (s[2] && s[0]=='r' && s[1]=='z')
X		Topipe=TRUE;
X}
X#endif
X
X/*
X * Totalitarian Communist pathname processing
X */
Xcheckpath(name)
Xchar *name;
X{
X	if (Restricted) {
X		if (fopen(name, "r") != NULL) {
X			canit();
X			fprintf(stderr, "\r\nrz: %s exists\n", name);
X			bibi(-1);
X		}
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\nrz:\tSecurity Violation\r\n");
X			bibi(-1);
X		}
X	}
X}
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 c, n;
X	register cmdzack1flg;
X
X	if (Nozmodem)		/* Check for "rb" program name */
X		return 0;
X
X
X	for (n=Zmodem?15:5; --n>=0; ) {
X		/* Set buffer length (0) and capability flags */
X#ifdef SEGMENTS
X		stohdr(SEGMENTS*1024L);
X#else
X		stohdr(0L);
X#endif
X#ifdef CANBREAK
X		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
X#else
X		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
X#endif
X		if (Zctlesc)
X			Txhdr[ZF0] |= TESCCTL;
X		zshhdr(tryzhdrtype, Txhdr);
X		if (tryzhdrtype == ZSKIP)	/* Don't skip too far */
X			tryzhdrtype = ZRINIT;	/* CAF 8-21-87 */
Xagain:
X		switch (zgethdr(Rxhdr, 0)) {
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			c = zrdata(secbuf, 1024);
X			mode(3);
X			if (c == GOTCRCW)
X				return ZFILE;
X			zshhdr(ZNAK, Txhdr);
X			goto again;
X		case ZSINIT:
X			Zctlesc = TESCCTL & Rxhdr[ZF0];
X			if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
X				stohdr(1L);
X				zshhdr(ZACK, Txhdr);
X				goto again;
X			}
X			zshhdr(ZNAK, Txhdr);
X			goto again;
X		case ZFREECNT:
X			stohdr(getfree());
X			zshhdr(ZACK, Txhdr);
X			goto again;
X		case ZCOMMAND:
X#ifdef vax11c
X			return ERROR;
X#else
X			cmdzack1flg = Rxhdr[ZF0];
X			if (zrdata(secbuf, 1024) == GOTCRCW) {
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<20 && zgethdr(Rxhdr,1) != ZFIN);
X				ackbibi();
X				if (cmdzack1flg & ZCACK1)
X					exec2(secbuf);
X				return ZCOMPL;
X			}
X			zshhdr(ZNAK, Txhdr); goto again;
X#endif
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 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 c, n;
X	long rxbytes;
X
X	Eofseen=FALSE;
X	if (procheader(secbuf) == ERROR) {
X		return (tryzhdrtype = ZSKIP);
X	}
X
X	n = 20; rxbytes = 0l;
X
X	for (;;) {
X#ifdef SEGMENTS
X		chinseg = 0;
X#endif
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#ifdef SEGMENTS
X			putsec(secbuf, chinseg);
X			chinseg = 0;
X#endif
X			if ( --n < 0) {
X				vfile("rzfile: zgethdr returned %d", c);
X				return ERROR;
X			}
X		case ZFILE:
X			zrdata(secbuf, 1024);
X			continue;
X		case ZEOF:
X#ifdef SEGMENTS
X			putsec(secbuf, chinseg);
X			chinseg = 0;
X#endif
X			if (rclhdr(Rxhdr) != rxbytes) {
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				errors = 0;  goto nxthdr;
X			}
X			if (closeit()) {
X				tryzhdrtype = ZFERR;
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#ifdef SEGMENTS
X			putsec(secbuf, chinseg);
X			chinseg = 0;
X#endif
X			if ( --n < 0) {
X				vfile("rzfile: zgethdr returned %d", c);
X				return ERROR;
X			}
X			zmputs(Attn);
X			continue;
X		case ZSKIP:
X#ifdef SEGMENTS
X			putsec(secbuf, chinseg);
X			chinseg = 0;
X#endif
X			closeit();
X			vfile("rzfile: Sender SKIPPED file");
X			return c;
X		case ZDATA:
X			if (rclhdr(Rxhdr) != rxbytes) {
X				if ( --n < 0) {
X					return ERROR;
X				}
X#ifdef SEGMENTS
X				putsec(secbuf, chinseg);
X				chinseg = 0;
X#endif
X				zmputs(Attn);  continue;
X			}
Xmoredata:
X			if (Verbose>1)
X				fprintf(stderr, "\r%7ld ZMODEM%s    ",
X				  rxbytes, Crc32?" CRC-32":"");
X#ifdef SEGMENTS
X			if (chinseg >= (1024 * SEGMENTS)) {
X				putsec(secbuf, chinseg);
X				chinseg = 0;
X			}
X			switch (c = zrdata(secbuf+chinseg, 1024))
X#else
X			switch (c = zrdata(secbuf, 1024))
X#endif
X			{
X			case ZCAN:
X#ifdef SEGMENTS
X				putsec(secbuf, chinseg);
X				chinseg = 0;
X#endif
X				vfile("rzfile: zgethdr returned %d", c);
X				return ERROR;
X			case ERROR:	/* CRC error */
X#ifdef SEGMENTS
X				putsec(secbuf, chinseg);
X				chinseg = 0;
X#endif
X				if ( --n < 0) {
X					vfile("rzfile: zgethdr returned %d", c);
X					return ERROR;
X				}
X				zmputs(Attn);
X				continue;
X			case TIMEOUT:
X#ifdef SEGMENTS
X				putsec(secbuf, chinseg);
X				chinseg = 0;
X#endif
X				if ( --n < 0) {
X					vfile("rzfile: zgethdr returned %d", c);
X					return ERROR;
X				}
X				continue;
X			case GOTCRCW:
X				n = 20;
X#ifdef SEGMENTS
X				chinseg += Rxcount;
X				putsec(secbuf, chinseg);
X				chinseg = 0;
X#else
X				putsec(secbuf, Rxcount);
X#endif
X				rxbytes += Rxcount;
X				stohdr(rxbytes);
X				zshhdr(ZACK, Txhdr);
X				sendline(XON);
X				goto nxthdr;
X			case GOTCRCQ:
X				n = 20;
X#ifdef SEGMENTS
X				chinseg += Rxcount;
X#else
X				putsec(secbuf, Rxcount);
X#endif
X				rxbytes += Rxcount;
X				stohdr(rxbytes);
X				zshhdr(ZACK, Txhdr);
X				goto moredata;
X			case GOTCRCG:
X				n = 20;
X#ifdef SEGMENTS
X				chinseg += Rxcount;
X#else
X				putsec(secbuf, Rxcount);
X#endif
X				rxbytes += Rxcount;
X				goto moredata;
X			case GOTCRCE:
X				n = 20;
X#ifdef SEGMENTS
X				chinseg += Rxcount;
X#else
X				putsec(secbuf, Rxcount);
X#endif
X				rxbytes += Rxcount;
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 c;
X
X	while (*s) {
X		switch (c = *s++) {
X		case '\336':
X			sleep(1); continue;
X		case '\335':
X			sendbrk(); continue;
X		default:
X			sendline(c);
X		}
X	}
X}
X
X/*
X * Close the receive dataset, return OK or ERROR
X */
Xcloseit()
X{
X#ifndef vax11c
X	if (Topipe) {
X		if (pclose(fout)) {
X			return ERROR;
X		}
X		return OK;
X	}
X#endif
X	if (fclose(fout)==ERROR) {
X		fprintf(stderr, "file close ERROR\n");
X		return ERROR;
X	}
X#ifndef vax11c
X	if (Modtime) {
X		timep[0] = time(NULL);
X		timep[1] = Modtime;
X		utime(Pathname, timep);
X	}
X#endif
X	if ((Filemode&S_IFMT) == S_IFREG)
X		chmod(Pathname, (07777 & Filemode));
X	return OK;
X}
X
X/*
X * Ack a ZFIN packet, let byegones be byegones
X */
Xackbibi()
X{
X	register n;
X
X	vfile("ackbibi:");
X	Readnum = 1;
X	stohdr(0L);
X	for (n=3; --n>=0; ) {
X		purgeline();
X		zshhdr(ZFIN, Txhdr);
X		switch (readline(100)) {
X		case 'O':
X			readline(1);	/* Discard 2nd 'O' */
X			vfile("ackbibi complete");
X			return;
X		case RCDO:
X			return;
X		case TIMEOUT:
X		default:
X			break;
X		}
X	}
X}
X
X
X
X/*
X * Local console output simulation
X */
Xbttyout(c)
X{
X	if (Verbose || Fromcu)
X		putc(c, stderr);
X}
X
X#ifndef vax11c
X/*
X * Strip leading ! if present, do shell escape. 
X */
Xsys2(s)
Xregister char *s;
X{
X	if (*s == '!')
X		++s;
X	return system(s);
X}
X/*
X * Strip leading ! if present, do exec.
X */
Xexec2(s)
Xregister char *s;
X{
X	if (*s == '!')
X		++s;
X	mode(0);
X	execl("/bin/sh", "sh", "-c", s);
X}
X#endif
X/* End of rz.c */
SHAR_EOF
chmod 0644 rz.c || echo "restore of rz.c fails"
fi
if test -f sz.1; then echo "File sz.1 exists"; else
echo "x - extracting sz.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > sz.1 &&
X'\" Revision Level 
X'\" Last Delta     04-21-88
X.TH SZ 1 OMEN
X.SH NAME
Xsx, sb, sz \- XMODEM, YMODEM, ZMODEM file send
X.SH SYNOPSIS
Xsz
X.RB [\- +abdefkLlNnopqTtuvyY ]
X.I file ...
X.br
Xsb
X.RB [\- adfkqtuv ]
X.I file ...
X.br
Xsx
X.RB [\- akqtuv ]
X.I file
X.br
Xsz
X.RB [\- oqtv ]
X.B "-c COMMAND"
X.br
Xsz
X.RB [\- oqtv ]
X.B "-i COMMAND"
X.br
Xsz -TT
X.SH DESCRIPTION
X.B Sz
Xuses the ZMODEM, YMODEM or XMODEM error correcting protocol to send
Xone or more files over a dial-in serial port to a variety of programs running under
XPC-DOS, CP/M, Unix, VMS, and other operating systems.
X
XWhile
X.I rz
Xis smart enough to be called from
X.I cu(1),
Xvery few versions of
X.I cu(1)
Xare smart enough to allow
X.I sz
Xto work properly.
XUnix flavors of Professional-YAM are available for such dial-out application.
X
X
X.B Sz
Xsends one or more files with ZMODEM protocol.
X
XZMODEM
Xgreatly simplifies file transfers compared to XMODEM.
XIn addition to a friendly user interface, ZMODEM
Xprovides Personal Computer and other users
Xan efficient, accurate, and robust file transfer method.
X
XZMODEM provides complete
X.B "END-TO-END"
Xdata integrity between application programs.
XZMODEM's 32 bit CRC catches errors
Xthat sneak into even the most advanced networks.
X
XAdvanced file management features include
XAutoDownload (Automatic file Download initiated without user intervention),
XDisplay of individual and total file lengths and transmission time estimates,
XCrash Recovery,
Xselective file transfers,
Xand preservation of
Xexact file date and length.
X
XOutput from another program may be piped to
X.B sz
Xfor transmission by denoting standard input with "-":
X.ce
Xls -l | sz -
XThe program output is transmitted with the filename sPID.sz
Xwhere PID is the process ID of the
X.B sz
Xprogram.
XIf the environment variable
X.B ONAME
Xis set, that is used instead.
XIn this case, the Unix command:
X.ce
Xls -l | ONAME=con sz -ay -
Xwill send a "file" to the PC-DOS console display.
XThe
X.B -y
Xoption instructs the receiver to open the file for writing unconditionally.
XThe
X.B -a
Xoption
Xcauses the receiver to convert Unix newlines to PC-DOS carriage returns
Xand linefeeds.
X
X
X.B Sb
Xbatch sends one or more files with YMODEM or ZMODEM protocol.
XThe initial ZMODEM initialization is not sent.
XWhen requested by the receiver,
X.B sb
Xsupports
X.B YMODEM-g
Xwith "cbreak" tty mode, XON/XOFF flow control,
Xand interrupt character set to CAN (^X).
X.B YMODEM-g
X(Professional-YAM
X.B g
Xoption)
Xincreases throughput over error free channels
X(direct connection, X.PC, etc.)
Xby not acknowledging each transmitted sector.
X
XOn
X.SM Unix
Xsystems, additional information about the file is transmitted.
XIf the receiving program uses this information,
Xthe transmitted file length controls the exact number of bytes written to
Xthe output dataset,
Xand the modify time and file mode
Xare set accordingly.
X
X
X.B Sx
Xsends a single
X.I file
Xwith
X.B XMODEM
Xor
X.B XMODEM-1k
Xprotocol
X(sometimes incorrectly called "ymodem").
XThe user must supply the file name to both sending and receiving programs.
X
XIff
X.B sz
Xis invoked with $SHELL set and iff that variable contains the
Xstring
X.I "rsh"
Xor
X.I "rksh"
X(restricted shell),
X.B sz
Xoperates in restricted mode.
XRestricted mode restricts pathnames to the current directory and
XPUBDIR (usually /usr/spool/uucppublic) and/or subdirectories
Xthereof.
X
X
XThe fourth form sends a single COMMAND to a ZMODEM receiver for execution.
X.B Sz
Xexits with the COMMAND return value.
XIf COMMAND includes spaces or characters special to the shell,
Xit must be quoted.
X
X
XThe fifth form sends a single COMMAND to a ZMODEM receiver for execution.
X.B Sz
Xexits as soon as the receiver has correctly received the command,
Xbefore it is executed.
X
X
XThe sixth form (sz -TT)
Xattempts to output all 256 code combinations to the terminal.
XIn you are having difficulty sending files,
Xthis command lets you see which character codes are being
Xeaten by the operating system.
X
X
XIf
X.B sz
Xis invoked with stdout and stderr to different datasets,
XVerbose is set to 2, causing frame by frame progress reports
Xto stderr.
XThis may be disabled with the
X.B q
Xoption.
X.PP
XThe meanings of the available options are:
X.PP
X.PD 0
X.TP
X.B
X\\
X.R
X(VMS) Force the next option letter to upper case.
X.TP
X.B +
XInstruct the receiver to append transmitted data to an existing file
X(ZMODEM only).
X.TP
X.B a
XConvert NL characters in the transmitted file to CR/LF.
XThis is done by the sender for XMODEM and YMODEM, by the receiver
Xfor ZMODEM.
X.TP
X.B b
X(ZMODEM) Binary override: transfer file without any translation.
X.TP
X.B "c COMMAND"
XSend COMMAND to the receiver for execution, return with COMMAND\'s exit status.
X.TP
X.B d
XChange all instances of "." to "/" in the transmitted pathname.
XThus, C.omenB0000 (which is unacceptable to MSDOS or CP/M)
Xis transmitted as C/omenB0000.
XIf the resultant filename has more than 8 characters in the stem,
Xa "." is inserted to allow a total of eleven.
X.TP
X.B e
XEscape all control characters;
Xnormally XON, XOFF, DLE, CR-@-CR, and Ctrl-X are escaped.
X.TP
X.B f
XSend Full pathname.
XNormally directory prefixes are stripped from the transmitted
Xfilename.
X.TP
X.B "i COMMAND"
XSend COMMAND to the receiver for execution, return Immediately
Xupon the receiving program's successful recption of the command.
X.TP
X.B k
X(XMODEM/YMODEM) Send files using 1024 byte blocks
Xrather than the default 128 byte blocks.
X1024 byte packets speed file transfers at high bit rates.
X(ZMODEM streams the data for the best possible throughput.)
X.TP
X.B "L N"
XUse ZMODEM sub-packets of length N.
XA larger N (32 <= N <= 1024) gives slightly higher throughput,
Xa smaller N speeds error recovery.
XThe default is 128 below 300 baud, 256 above 300 baud, or 1024 above 2400 baud.
X.TP
X.B "l N"
XWait for the receiver to acknowledge correct data every
X.B N
X(32 <= N <= 1024)
Xcharacters.
XThis may be used to avoid network overrun when XOFF flow control is lacking.
X.TP
X.B n
X(ZMODEM) Send each file if
Xdestination file does not exist.
XOverwrite destination file if
Xsource file is newer than the destination file.
X.TP
X.B N
X(ZMODEM) Send each file if
Xdestination file does not exist.
XOverwrite destination file if
Xsource file is newer or longer than the destination file.
X.TP
X.B o
X(ZMODEM) Disable automatic selection of 32 bit CRC.
X.TP
X.B p
X(ZMODEM) Protect existing destination files by skipping transfer if the
Xdestination file exists.
X.TP
X.B q
XQuiet suppresses verbosity.
X.TP
X.B r
X(ZMODEM) Resume interrupted file transfer.
XIf the source file is longer than the destination file,
Xthe transfer commences at the offset in the source file that equals
Xthe length of the destination file.
X.TP
X.B "t tim"
XChange timeout to
X.I tim
Xtenths of seconds.
X.TP
X.B u
XUnlink the file after successful transmission.
X.TP
X.B "w N"
XLimit the transmit window size to N bytes (ZMODEM).
X.TP
X.B v
XVerbose
Xcauses a list of file
Xnames to be appended to
X/tmp/szlog .
XMore v's generate more output.
X.TP
X.B y
XInstruct a ZMODEM receiving program to overwrite any existing file
Xwith the same name.
X.TP
X.B Y
XInstruct a ZMODEM receiving program to overwrite any existing file
Xwith the same name,
Xand to skip any source files that do have a file with the same
Xpathname on the destination system.
X.PD
X.SH EXAMPLES
X.ne 7
X.B "ZMODEM File Transfer"
X(Unix to DSZ/ZCOMM/Professional-YAM)
X.br
X.B "% sz \-a *.c"
X.br
XThis single command transfers all .c files in the current Unix directory
Xwith conversion
X.RB ( \-a )
Xto end of line conventions appropriate to the receiving environment.
XWith ZMODEM AutoDownload enabled, Professional-YAM  and ZCOMM
Xwill automatically recieve
Xthe files after performing a security check.
X
X.br
X.B "% sz \-Yan *.c *.h"
X.br
XSend only the .c and .h files that exist on both systems,
Xand are newer on the sending system than the
Xcorresponding version on the receiving system, converting Unix to
XDOS text format.
X.br
X.B
X$ sz -\\Yan file1.c file2.c file3.c foo.h baz.h
X.R
X(for VMS)
X.br
X
X.B "ZMODEM Command Download"
X(Unix to Professional-YAM)
X.br
X cpszall:all
X    sz \-c "c:;cd /yam/dist"
X    sz \-ya $(YD)/*.me
X    sz \-yqb y*.exe
X    sz \-c "cd /yam"
X    sz \-i "!insms"
X.br
XThis Makefile fragment uses
X.B sz
Xto issue commands to Professional-YAM to change current disk and directory.
XNext,
X.B sz
Xtransfers the
X.I .me
Xfiles from the $YD directory, commanding the receiver to overwrite the old files
Xand to convert from Unix end of line conventions to PC-DOS conventions.
XThe third line transfers some
X.I .exe
Xfiles.
XThe fourth and fifth lines command Pro-YAM to
Xchange directory and execute a PC-DOS batch file
X.I insms .
XSince the batch file takes considerable time, the
X.B "\-i"
Xform is used to allow
X.B sz
Xto exit immediately.
X
X.B "XMODEM File Transfer"
X(Unix to Crosstalk)
X.br
X%
X.B "sx \-a foo.c"
X.br
X.B "ESC"
X.br
X.B "rx foo.c"
X.br
XThe above three commands transfer a single file
Xfrom Unix to a PC and Crosstalk with
X.I sz
Xtranslating Unix newlines to DOS CR/LF.
XThis combination is much slower and far less reliable than ZMODEM.
X.SH ERROR MESSAGES
X"Caught signal 99"
Xindicates the program was not properly compiled,
Xrefer to "bibi(99)" in rbsb.c for details.
X.SH SEE ALSO
Xrz(omen),
XZMODEM.DOC,
XYMODEM.DOC,
XProfessional-YAM,
Xcrc(omen),
Xsq(omen),
Xtodos(omen),
Xtocpm(omen),
Xtomac(omen),
Xyam(omen)
X
XCompile time options required for various operating systems are described in
Xthe source file.
X.SH "VMS VERSION"
XThe VMS version does not support wild cards.
XBecause of VMS DCL, upper case option letters muse be represented
Xby \\ proceding the letter.
X
XThe current VMS version does not support XMODEM, XMODEM-1k, or YMODEM.
X
XVMS C Standard I/O and RMS may interact to modify the file contents.
X.SH FILES
X32 bit CRC code courtesy Gary S. Brown.
X
Xsz.c, crctab.c, rbsb.c, zm.c, zmodem.h Unix source files
X
Xsz.c, crctab.c, vrzsz.c, zm.c, zmodem.h, vmodem.h, vvmodem.c,
XVMS source files.
X
X/tmp/szlog stores debugging output (sz -vv)
X(szlog on VMS).
X.SH "TESTING FEATURE"
XThe command "sz -T file"
Xexercises the
X.B Attn
Xsequence error recovery by commanding
Xerrors with unterminated packets.
XThe receiving program should complain five times about
Xbinary data packets being too long.
XEach time
X.B sz
Xis interrupted,
Xit should send a ZDATA header followed by another defective packet.
XIf the receiver does not detect five long data packets,
Xthe
X.B Attn
Xsequence is not interrupting the sender, and the
X.B Myattn
Xstring in
X.B sz.c
Xmust be modified.
X
XAfter 5 packets,
X.B sz
Xstops the "transfer" and
Xprints the total number of characters "sent" (Tcount).
XThe difference between Tcount and 5120 represents the number of characters
Xstored in various buffers when the Attn sequence is generated.
X.SH BUGS
XCalling
X.I sz
Xfrom most versions of cu(1) doesn't work because cu's receive process
Xfights
X.I sz
Xfor characters from the modem.
X
XPrograms that do not properly implement the specified file transfer protocol
Xmay cause
X.I sz
Xto "hang" the port for a minute or two.
XEvery reported instance of this problem has been corrected by using
XZCOMM, Pro-YAM, or other program with a correct implementation
Xof the specified protocol.
X
XMany programs claiming to support YMODEM only support XMODEM with 1k blocks,
Xand they often don't get that quite right.
X
XXMODEM transfers add up to 127 garbage bytes per file.
XXMODEM-1k and YMODEM-1k transfers use 128 byte blocks
Xto avoid extra padding.
X
XYMODEM programs use the file length transmitted at the beginning of the
Xtransfer to prune the file to the correct length; this may cause problems with
Xsource files that grow during the course of the transfer.
XThis problem does not pertain to ZMODEM transfers, which preserve the exact
Xfile length unconditionally.
X
XMost ZMODEM options are merely passed to the receiving program;
SHAR_EOF
echo "End of part 2"
echo "File sz.1 is continued in part 3"
echo "3" > ._seq_
-- 
Keith Petersen
Arpa: W8SDZ@SIMTEL20.ARPA
Uucp: {bellcore,decwrl,harvard,lll-crg,ucbvax,uw-beaver}!simtel20.arpa!w8sdz
GEnie: W8SDZ