Browse Source

添加 zmodem

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1302 bbd45198-f89e-11dd-88c7-29a3b14d5316
itspy.wei 14 years ago
parent
commit
6f4ad3b626

+ 24 - 0
components/utilities/ZMODEM/RBSB.C

@@ -0,0 +1,24 @@
+/* -rev 05-12-86
+ * mode function and most of the rest of the system dependent
+ * stuff for rb.c and sb.c   This file is #included so the includer
+ * can set parameters such as HOWMANY.
+ */
+
+int iofd = 0;		/* File descriptor for ioctls & reads */
+
+/*
+ * mode(n)
+ *  2: set a cbreak, XON/XOFF control mode if using Pro-YAM's -g option
+ *  1: save old tty stat, set raw mode 
+ *  0: restore original tty mode
+ */
+int mode(int n)
+{
+    return 0;
+}
+
+int sendbrk()
+{
+	//ioctl(iofd, TCSBRK, 0);
+	return 0;
+}

+ 269 - 0
components/utilities/ZMODEM/RZ.1

@@ -0,0 +1,269 @@
+'\" Revision Level 
+'\" Last Delta     05-19-86
+.TH RZ 1 OMEN
+.SH NAME
+rb, rz \- XMODEM, YMODEM, ZMODEM (Batch) file receive
+.SH SYNOPSIS
+.B rz
+.RB [\- "\ 1bquv" ]
+.br
+.B rb
+.RB [\- "\ 1bquv" ]
+.br
+.B rz
+.RB [\- "\ 1bcquv" ]
+.I file
+.br
+.RB [ \- ][ v ] rzCOMMAND
+.SH DESCRIPTION
+This program uses error correcting protocol to receive
+files over a serial port from a variety of programs running under
+PC-DOS, CP/M,
+.SM Unix,
+and other operating systems.
+
+The first form of
+.B rz
+(Receive Batch)
+receives files with ZMODEM batch protocol.
+If the sending program does not support ZMODEM,
+.B rz
+steps down to YMODEM protocol
+after 50 seconds.
+This delay can be eliminated by calling the program as
+.I rb .
+
+.B Rb
+accepts either standard 128 byte sectors or
+1024 byte sectors
+(YAM
+.B -k
+option).
+The user should determine experimentally
+the conditions under which use of 1k blocks
+actually improves throughput without causing
+problems.
+
+Normally, the file contents are converted to
+.SM Unix
+conventions by stripping carriage returns and all characters
+beginning with Control Z (CP/M end of file).
+If the raw pathname ends in
+".A",
+".ARC",
+".CCC",
+".CL",
+".CMD",
+".COM",
+".CRL",
+".DAT",
+".DIR",
+".EXE",
+".O",
+".OBJ",
+".OVL",
+".PAG",
+".REL",
+".SAV",
+".SUB",
+".SWP",
+".SYS",
+".TAR",
+".UTL",
+".a",
+".o",
+".tar",
+or if the first packet contains
+data that suggest a binary file
+(parity bits or characters in the range 000 to 006 before the first ^Z),
+or if the file mode is transmitted and the 0100000
+bit is set, that file will be received in binary mode anyway.
+Otherwise,
+if the raw pathname ends in .MSG, or .TXT, an existing file will
+be appended to rather than replaced.
+
+If extended file information (file length, etc.)
+is received,
+the file length controls the number of bytes written to
+the output dataset (YMODEM only),
+and the modify time and file mode
+(iff non zero)
+are set accordingly.
+
+If no extended file information is received,
+slashes in the pathname are changed to underscore,
+and any trailing period in the pathname is eliminated.
+This conversion is useful for files received from CP/M systems.
+Normally, each file name is converted to lower case
+unless it contains one or more lower case letters.
+
+
+The second form of
+.B rz
+receives a single
+.I file
+with XMODEM protocol.
+The user must supply the file name to both sending and receiving programs.
+
+
+The third form of
+.B rz
+is invoked as
+.B rzCOMMAND
+(with an optional leading \- as generated by login(1)).
+For each received file,
+rz will pipe the file to ``COMMAND filename''
+where filename is the name of the transmitted file
+with the file contents as standard input.
+
+Each file transfer is acknowledged when COMMAND exits with 0 status.
+A non zero exit status terminates transfers.
+
+A typical use for this form is
+.I rzrmail
+which calls rmail(1)
+to post mail to the user specified by the transmitted file name.
+For example, sending the file "caf" from a PC-DOS system to
+.I rzrmail
+on a
+.SM Unix
+system
+would result in the contents of the DOS file "caf" being mailed to user "caf".
+
+On some
+.SM Unix
+systems, the login directory must contain a link to
+COMMAND as login sets SHELL=rsh which disallows absolute
+pathnames.
+If invoked with a leading ``v'',
+.B rz
+will report progress to LOGFILE.
+The following entry works for
+.SM Unix
+3.0:
+.ce
+rzrmail::5:1::/bin:/usr/local/rzrmail
+If the SHELL environment variable includes
+.I "rsh"
+or
+.I "rksh"
+(restricted shell),
+rz will not accept absolute pathnames
+or references to a parent directory,
+will not modify an existing file, and
+removes any files received in error.
+
+If
+.B rz
+is invoked with stdout and stderr to different datasets,
+Verbose is set to 2, causing frame by frame progress reports
+to stderr.
+This may be disabled with the
+.B q
+option.
+
+.PP
+The meanings of the available options are:
+.PP
+.PD 0
+.TP
+.B 1
+Use file descriptor 1 for ioctls and reads (Unix only).
+By default, file descriptor 0 is used.
+This option allows
+.B rz
+to be used with the
+.I cu
+~$
+command.
+.TP
+.B b
+Transfer all files in binary
+(tell it like it is)
+mode.
+This option disables file append.
+.TP
+.B c
+Request 16 bit CRC
+(XMODEM file transfers default to 8 bit checksum).
+Batch transfers use 16 bit CRC.
+.TP
+.B D
+Output file data to /dev/null; for testing.
+.TP
+.B q
+Quiet suppresses verbosity.
+.TP
+.B v
+Verbose
+causes a list of file
+names to be appended to
+/tmp/rzlog .
+More v's generate more output.
+.TP
+.B u
+Retain upper case letters in file names.
+.PD
+.SH EXAMPLES
+.ne 6
+.RE
+(Pro-YAM command)
+.RS
+.I <ALT-2>
+.br
+YAM Command:
+.I "sz *.h *.c"
+.br
+(This automatically invokes
+.I rz
+on the connected system.)
+.RE
+.SH SEE ALSO
+ZMODEM.DOC,
+YMODEM.DOC,
+IMP(CP/M),
+cu(1),
+Professional-YAM manual,
+sz(omen),
+usq(omen),
+undos(omen)
+
+Compile time options required
+for various operating systems are described in the
+source file.
+.SH BUGS
+Pathnames are restricted to 127 characters.
+In XMODEM single file mode, the pathname given on the command line
+is still processed as described above.
+The CR/LF to NL translation merely deletes CR\'s;
+undos(omen) performs a more intelligent translation.
+.SH "VMS VERSION"
+Some of the #includes with file names enclosed with angle brackets <>
+may need to have the angle brackets changed to "", or vice versa.
+
+The VMS version does not set binary mode according to the incoming
+file type.
+Non binary file processing consists of stripping all characters beginning
+with CPMEOF (^Z).
+
+The VMS version does not set the file time.
+
+At high speeds,
+VMS sometimes loses incoming characters, resulting in retries
+and degradation of throughput.
+
+The mysterious
+VMS C Standard I/O Package and RMS may interact to modify
+file contents unexpectedly.
+
+The VMS version does not support invocation as
+.B rzCOMMAND .
+ZMODEM has not yet been implemented on the VMS version.
+.SH "ZMODEM CAPABILITIES"
+.B Rz
+supports incoming ZMODEM binary (-b), ASCII (-a), and append (-+)
+requests, and ZMODEM command execution.
+.SH FILES
+rz.c, rbsb.c, zm.c, zmodem.h source files.
+
+/tmp/rzlog stores debugging output generated with -vv option.

+ 1104 - 0
components/utilities/ZMODEM/RZ.C

@@ -0,0 +1,1104 @@
+#define VERSION "1.03 05-18-86"
+#define PUBDIR "/usr/spool/uucppublic"
+
+/*% cc -DNFGVMIN -K -O % -o rz; size rz
+ *
+ * rz.c By Chuck Forsberg
+ *
+ *	cc -O rz.c -o rz		USG (3.0) Unix
+ * 	cc -O -DV7  rz.c -o rz		Unix V7, BSD 2.8 - 4.3
+ *
+ *	ln rz rb			For either system
+ *
+ *	ln rz /usr/bin/rbrmail		For remote mail.  Make this the
+ *					login shell. rbrmail then calls
+ *					rmail(1) to deliver mail.
+ *
+ *  Unix is a trademark of Western Electric Company
+ *
+ * A program for Unix to receive files and commands from computers running
+ *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
+ *  rz uses Unix buffered input to reduce wasted CPU time.
+ *
+ * Iff the program is invoked by rzCOMMAND, output is piped to 
+ * "COMMAND filename"
+ *
+ *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
+ *  read(2) the same way as Unix. ONEREAD must be defined to force one
+ *  character reads for these systems. Added 7-01-84 CAF
+ *
+ *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
+ *
+ *  NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
+ *  doesn't seem to work (even though it compiles without error!).
+ *
+ *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
+ */
+#define zperr vfile
+
+#include "rtthread.h"
+#include "finsh.h"
+#include "shell.h"	
+#include"rtdef.h"
+#include <dfs.h>
+#include <dfs_file.h>
+#include <dfs_posix.h>
+
+
+#define OK 0
+#define FALSE 0
+#define TRUE 1
+#define ERROR (-1)
+
+#define HOWMANY 133
+int Zmodem=0;		/* ZMODEM protocol requested */
+int Nozmodem = 0;	/* If invoked as "rb" */
+unsigned Baudrate;
+#include "rbsb.c"	/* most of the system dependent stuff here */
+
+
+int fout;
+
+/*
+ * Routine to calculate the free bytes on the current file system
+ *  ~0 means many free bytes (unknown)
+ */
+long getfree()
+{
+	return(~0L);	/* many free bytes ... */
+}
+
+char *Extensions[] = {
+".A",
+".ARC",
+".CCC",
+".CL",
+".CMD",
+".COM",
+".CRL",
+".DAT",
+".DIR",
+".EXE",
+".O",
+".OBJ",
+".OVL",
+".PAG",
+".REL",
+".SAV",
+".SUB",
+".SWP",
+".SYS",
+".TAR",
+".UTL",
+".a",
+".arc",
+".com",
+".dat",
+".o",
+".obj",
+".ovl",
+".sys",
+".tar",
+""
+};
+
+/* Ward Christensen / CP/M parameters - Don't change these! */
+#define ENQ 005
+#define CAN ('X'&037)
+#define XOFF ('s'&037)
+#define XON ('q'&037)
+#define SOH 1
+#define STX 2
+#define EOT 4
+#define ACK 6
+#define NAK 025
+#define CPMEOF 032
+#define WANTCRC 0103	/* send C not NAK to get crc not checksum */
+#define TIMEOUT (-2)
+#define ERRORMAX 5
+#define RETRYMAX 5
+#define WCEOT (-10)
+#define SECSIZ 128	/* cp/m's Magic Number record size */
+#define PATHLEN 257	/* ready for 4.2 bsd ? */
+#define KSIZE 1024	/* record size with k option */
+#define UNIXFILE 0x8000	/* happens to the the S_IFREG file mask bit for stat */
+
+int Lastrx;
+int Crcflg;
+int Firstsec;
+int Eofseen;		/* indicates cpm eof (^Z) has been received */
+int errors;
+int Restricted=0;	/* restricted; no /.. or ../ in filenames */
+int Badclose = 0;	/* Error on last close */ 
+#define ONEREAD 1
+#ifdef ONEREAD
+/* Sorry, Regulus and some others don't work right in raw mode! */
+int Readnum = 1;	/* Number of bytes to ask for in read() from modem */
+#else
+int Readnum = KSIZE;	/* Number of bytes to ask for in read() from modem */
+#endif
+
+#define DEFBYTL 2000000000L	/* default rx file size */
+long Bytesleft;		/* number of bytes of incoming file left */
+long Modtime;		/* Unix style mod time for incoming file */
+short Filemode;		/* Unix style mode for incoming file */
+char Pathname[PATHLEN];
+char *Progname;		/* the name by which we were called */
+
+int Batch=0;
+int Wcsmask=0377;
+int Topipe=0;
+int MakeLCPathname=TRUE;	/* make received pathname lower case */
+int Verbose=0;
+int Quiet=0;		/* overrides logic that would otherwise set verbose */
+int Nflag = 0;		/* Don't really transfer files */
+int Rxbinary=FALSE;	/* receive all files in bin mode */
+int Thisbinary;		/* current file is to be received in bin mode */
+int Blklen;		/* record length of received packets */
+char secbuf[KSIZE];
+char linbuf[KSIZE];
+int Lleft=0;		/* number of characters in linbuf */
+
+char zconv;		/* ZMODEM file conversion request */
+char zmanag;		/* ZMODEM file management request */
+char ztrans;		/* ZMODEM file transport request */
+
+
+int purgeline(void);
+unsigned short int updcrc(int c, int crc);
+int procheader(char *name);
+int report(int sct);
+int tryz(void);
+int rzfiles(void);
+int rzfile(void);
+int closeit(void);
+int zmputs(char *s);
+int ackbibi(void);
+int wcreceive(int argc, char **argp);
+int wcrxpn(char *rpn);
+int wcrx(void);
+int wcgetsec(char *rxbuf, int maxtime);
+int readline(int timeout);
+int putsec(char *buf, int n);
+int sendline(int c);
+int xsendline(int c);
+int log(const char *s,...);
+int bttyout(int c);
+int flushmo(void);
+int canit(void);
+int sys2(char *s);
+int exec2(char *s);
+
+#include "zm.c"
+
+
+/* called by signal interrupt or terminate to clean things up */
+int bibi(int n)
+{
+	if (Zmodem)
+		zmputs(Attn);
+	canit(); 
+	mode(0);
+	return 0;
+}
+
+int zrmain(void)
+{
+	if (wcreceive(0, 0)==ERROR) {
+		canit();
+		zperr("received error,exit\n");
+        return 1;
+	}
+	return 0;
+}
+
+
+int usage(void)
+{
+	//rt_kprintf("%s %s for %s by Chuck Forsberg\n",
+	 // Progname, VERSION, OS);
+	//rt_kprintf("Usage:	rz [-1buv]		(ZMODEM Batch)\n");
+	//rt_kprintf("or	rb [-1buv]		(YMODEM Batch)\n");
+	//rt_kprintf("or	rz [-1bcv] file		(XMODEM)\n");
+	//rt_kprintf("	  -1 For cu(1): Use fd 1 for input\n");
+	//rt_kprintf("	  -b Binary transfer for all files\n");
+	//rt_kprintf("	  -u Allow all UPPER CASE names\n");
+	//rt_kprintf("	  -v Verbose more v's give more info\n");
+	//rt_kprintf("	  -c Use 16 bit CRC	(XMODEM)\n");
+	//exit(1);
+	return 0;
+}
+/*
+ *  Debugging information output interface routine
+ */
+/* VARARGS1 */
+void vfile(const char *fmt,...)
+{
+    return;
+}
+
+/*
+ * Let's receive something already.
+ */
+int wcreceive(int argc, char **argp)
+{
+	int c;
+
+	if (Batch || argc==0) {
+		Crcflg=(Wcsmask==0377);
+		if ( !Quiet)
+			rt_kprintf("\nrz: ready...\n");
+		c = tryz();
+		if (c) {
+			if (c == ZCOMPL)
+				return OK;
+			if (c == ERROR)
+				goto fubar;
+			c = rzfiles();
+			if (c)
+				goto fubar;
+		} else {
+			for (;;) {
+				if (wcrxpn(secbuf)== ERROR)
+					goto fubar;
+				if (secbuf[0]==0)
+					return OK;
+				if (procheader(secbuf) == ERROR)
+					goto fubar;
+				if (wcrx()==ERROR)
+					goto fubar;
+			}
+		}
+	} else {
+		Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
+
+		strcpy(Pathname, *argp);
+		//checkpath(Pathname);
+		//rt_kprintf(stderr, "\nrz: ready to receive %s ", Pathname);
+		//if ((fout=fopen(Pathname, "w")) == NULL)
+		//	return ERROR;
+		if (wcrx()==ERROR)
+			goto fubar;
+	}
+	return OK;
+fubar:
+	canit();
+	if (Topipe && fout) {
+		close(fout);  return ERROR;
+	}
+	if (fout)
+		close(fout);
+	if (Restricted) {
+		unlink(Pathname);
+		rt_kprintf("\r\nrz: %s removed.\r\n", Pathname);
+	}
+	return ERROR;
+}
+
+
+/*
+ * Fetch a pathname from the other end as a C ctyle ASCIZ string.
+ * Length is indeterminate as long as less than Blklen
+ * A null string represents no more files (YMODEM)
+ */
+int wcrxpn(char *rpn)
+{
+	int c;
+
+#ifdef NFGVMIN
+	readline(1);
+#else
+	purgeline();
+#endif
+
+et_tu:
+	Firstsec=TRUE;  Eofseen=FALSE;
+	sendline(Crcflg?WANTCRC:NAK);
+	Lleft=0;	/* Do read next time ... */
+	while ((c = wcgetsec(rpn, 100)) != 0) {
+		log( "Pathname fetch returned %d\n", c);
+		if (c == WCEOT) {
+			sendline(ACK);
+			Lleft=0;	/* Do read next time ... */
+			readline(1);
+			goto et_tu;
+		}
+		return ERROR;
+	}
+	sendline(ACK);
+	return OK;
+}
+
+/*
+ * Adapted from CMODEM13.C, written by
+ * Jack M. Wierda and Roderick W. Hart
+ */
+
+int wcrx(void)
+{
+	register int sectnum, sectcurr;
+	register char sendchar;
+	register char *p;
+	int cblklen;			/* bytes to dump this block */
+
+	Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
+	sendchar=Crcflg?WANTCRC:NAK;
+
+	for (;;) {
+		sendline(sendchar);	/* send it now, we're ready! */
+		Lleft=0;	/* Do read next time ... */
+		sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
+		report(sectcurr);
+		if (sectcurr==(sectnum+1 &Wcsmask)) {
+
+			if (sectnum==0 && !Thisbinary) {
+				p=secbuf;  sectcurr=Blklen;
+				if (*p == 032)	/* A hack for .arc files */
+					goto binbin;
+				for (; *p != 032 && --sectcurr>=0; ++p)
+					if (*p < 07 || (*p & 0200)) {
+binbin:
+						Thisbinary++;
+						if (Verbose)
+							rt_kprintf("Changed to BIN\n");
+						break;
+					}
+			}
+			sectnum++;
+			cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
+			if (putsec(secbuf, cblklen)==ERROR)
+				return ERROR;
+			if ((Bytesleft-=cblklen) < 0)
+				Bytesleft = 0;
+			sendchar=ACK;
+		}
+		else if (sectcurr==(sectnum&Wcsmask)) {
+			log( "Received dup Sector\n");
+			sendchar=ACK;
+		}
+		else if (sectcurr==WCEOT) {
+			if (closeit())
+				return ERROR;
+			sendline(ACK);
+			Lleft=0;	/* Do read next time ... */
+			return OK;
+		}
+		else if (sectcurr==ERROR)
+			return ERROR;
+		else {
+			log( "Sync Error\n");
+			return ERROR;
+		}
+	}
+}
+
+/*
+ * Wcgetsec fetches a Ward Christensen type sector.
+ * Returns sector number encountered or ERROR if valid sector not received,
+ * or CAN CAN received
+ * or WCEOT if eot sector
+ * time is timeout for first char, set to 4 seconds thereafter
+ ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
+ *    (Caller must do that when he is good and ready to get next sector)
+ */
+
+int wcgetsec(char *rxbuf, int maxtime)
+{
+	int checksum, wcj, firstch;
+    unsigned short oldcrc;
+    char *p;
+	int sectcurr;
+
+	for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
+
+		if ((firstch=readline(maxtime))==STX) {
+			Blklen=KSIZE; goto get2;
+		}
+		if (firstch==SOH) {
+			Blklen=SECSIZ;
+get2:
+			sectcurr=readline(1);
+			if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) {
+				oldcrc=checksum=0;
+				for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
+					if ((firstch=readline(1)) < 0)
+						goto bilge;
+					oldcrc=updcrc(firstch, oldcrc);
+					checksum += (*p++ = firstch);
+				}
+				if ((firstch=readline(1)) < 0)
+					goto bilge;
+				if (Crcflg) {
+					oldcrc=updcrc(firstch, oldcrc);
+					if ((firstch=readline(1)) < 0)
+						goto bilge;
+					oldcrc=updcrc(firstch, oldcrc);
+					if (oldcrc & 0xFFFF)
+						log("CRC=0%o\n", oldcrc);
+					else {
+						Firstsec=FALSE;
+						return sectcurr;
+					}
+				}
+				else if (((checksum-firstch)&Wcsmask)==0) {
+					Firstsec=FALSE;
+					return sectcurr;
+				}
+				else
+					log( "Checksum Error\n");
+			}
+			else
+				log("Sector number garbled 0%o 0%o\n",
+				 sectcurr, oldcrc);
+		}
+		/* make sure eot really is eot and not just mixmash */
+#ifdef NFGVMIN
+		else if (firstch==EOT && readline(1)==TIMEOUT)
+			return WCEOT;
+#else
+		else if (firstch==EOT && Lleft==0)
+			return WCEOT;
+#endif
+		else if (firstch==CAN) {
+			if (Lastrx==CAN) {
+				log("Sender CANcelled\n");
+				return ERROR;
+			} else {
+				Lastrx=CAN;
+				continue;
+			}
+		}
+		else if (firstch==TIMEOUT) {
+			if (Firstsec)
+				goto humbug;
+bilge:
+			log( "Timeout\n");
+		}
+		else
+			log( "Got 0%o sector header\n", firstch);
+
+humbug:
+		Lastrx=0;
+		while(readline(1)!=TIMEOUT)
+			;
+		if (Firstsec) {
+			sendline(Crcflg?WANTCRC:NAK);
+			Lleft=0;	/* Do read next time ... */
+		} else {
+			maxtime=40; sendline(NAK);
+			Lleft=0;	/* Do read next time ... */
+		}
+	}
+	/* try to stop the bubble machine. */
+	canit();
+	return ERROR;
+}
+
+/*
+ * This version of readline is reasoably well suited for
+ * reading many characters.
+ *  (except, currently, for the Regulus version!)
+ *
+ * timeout is in tenths of seconds
+ */
+int readline(int timeout)
+{
+	static char *cdq;	/* pointer for removing chars from linbuf */
+	static char data_buffer[8];
+	if (--Lleft >= 0) 
+	{
+		return (*cdq++ & Wcsmask);
+	}
+	while (1)
+	{    
+     	Lleft = zread(shell->device, 0, data_buffer, 1);
+		if (Lleft)
+		{
+		     Lleft = Lleft;
+		     cdq = &data_buffer[0];
+             break;
+		}
+	}
+
+	if (Lleft < 1)
+		return TIMEOUT;
+	--Lleft;
+	return (*cdq++ & Wcsmask);
+}
+
+
+
+/*
+ * Purge the modem input queue of all characters
+ */
+int purgeline(void)
+{
+
+	Lleft = 0;
+#ifdef USG
+	ioctl(iofd, TCFLSH, 0);
+#else
+	lseek(iofd, 0L, 2);
+#endif
+    return 0;
+}
+
+/*
+ * Update CRC CRC-16 used by XMODEM/CRC, YMODEM, and ZMODEM.
+ *  Note: Final result must be masked with 0xFFFF before testing
+ *  More efficient table driven routines exist.
+ */
+unsigned short int 
+updcrc(int c, int crc)
+{
+	int count;
+
+	for (count=8; --count>=0;) {
+		if (crc & 0x8000) {
+			crc <<= 1;
+			crc += (((c<<=1) & 0400)  !=  0);
+			crc ^= 0x1021;
+		}
+		else {
+			crc <<= 1;
+			crc += (((c<<=1) & 0400)  !=  0);
+		}
+	}
+	return crc;	
+}
+
+/*
+ * Process incoming file information header
+ */
+int procheader(char *name)
+{
+    char *openmode, *ptr;
+	unsigned char i;
+	char fname[100];
+	/* set default parameters */
+	openmode = "w"; Thisbinary=Rxbinary;
+
+	/*
+	 *  Process ZMODEM remote file management requests
+	 */
+	if (zconv == ZCNL)	/* Remote ASCII override */
+		Thisbinary = 0;
+	if (zconv == ZCBIN)	/* Remote Binary override */
+		++Thisbinary;
+	else if (zmanag == ZMAPND)
+		openmode = "a";
+	openmode = openmode;
+	Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
+	for(i=0;i<100;i++) fname[i] = 0;
+	for (i=1,ptr=name;i<strlen(name)+1;i++)	 /* get file name */
+	     fname[i]= *ptr++;
+	fname[0] = '/';			    /* working_directory */
+	if ((fout = open(fname,DFS_O_CREAT|DFS_O_WRONLY,0)) < 0)	 /* create file */
+	{
+		return ERROR;
+	}
+	return OK;
+}
+
+/* Make string s lower case */
+int uncaps(char *s)
+{
+    return 0;
+	/*
+	for ( ; *s; ++s)
+		if (isupper(*s))
+			*s = tolower(*s);
+	*/
+}
+
+
+/*
+ * IsAnyLower returns TRUE if string s has lower case letters.
+ */
+int IsAnyLower(char *s)
+{
+    return 0;
+/*
+	for ( ; *s; ++s)
+		if (islower(*s))
+			return TRUE;
+	return FALSE;
+	*/
+}
+/*
+ * Putsec writes the n characters of buf to receive file fout.
+ *  If not in binary mode, carriage returns, and all characters
+ *  starting with CPMEOF are discarded.
+ */
+int putsec(char *buf, int n)
+{
+	register char *p;
+
+	if (Thisbinary) {
+		for (p=buf; --n>=0; )
+			write(fout,p++,1);
+	}
+	else {
+		if (Eofseen)
+			return OK;
+		for (p=buf; --n>=0; ++p ) {
+			if ( *p == '\r')
+				continue;
+			if (*p == CPMEOF) {
+				Eofseen=TRUE; return OK;
+			}
+			write(fout,p,1);
+		}
+	}
+	return OK;
+}
+
+/*
+ *  Send a character to modem.  Small is beautiful.
+ */
+int sendline(int c)
+{
+	zwrite(c);
+	return 0;
+}
+
+int xsendline(int c)
+{
+	sendline(c);
+	return 0;
+}
+
+int flushmo(void) 
+{
+    return 0;
+}
+
+
+
+
+/*
+ * substr(string, token) searches for token in string s
+ * returns pointer to token within string if found, NULL otherwise
+ */
+char *
+substr(char *s, char *t)
+{
+	register char *ss,*tt;
+	/* search for first char of token */
+	for (ss=s; *s; s++)
+		if (*s == *t)
+			/* compare token with substring */
+			for (ss=s,tt=t; ;) {
+				if (*tt == 0)
+					return s;
+				if (*ss++ != *tt++)
+					break;
+			}
+	return NULL;
+}
+
+/*
+ * Log an error
+ */
+/*VARARGS1*/
+int log(const char *s,...)
+{
+    return 0;
+}
+
+/* send cancel string to get the other end to shut up */
+int canit(void)
+{  /*
+	static char canistr[] = {
+	 ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
+	};
+	*/
+	//printf(canistr);
+	Lleft=0;	/* Do read next time ... */
+	//fflush(stdout);
+	return 0;
+}
+
+
+/*
+ * Return 1 iff stdout and stderr are different devices
+ *  indicating this program operating with a modem on a
+ *  different line
+ */
+int fromcu(void)
+{
+	struct stat a, b;
+	fstat(1, &a);
+    fstat(2, &b);
+	//return (a.st_rdev != b.st_rdev);
+	return 0;
+}
+
+int report(int sct)
+{
+	//if (Verbose>1)
+	//	rt_kprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
+	return 0;
+}
+
+/*
+ * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
+ * If called as [-][dir/../]rzCOMMAND set the pipe flag
+ * If called as rb use YMODEM protocol
+ */
+int chkinvok(char *s)
+{
+	register char *p;
+
+	p = s;
+	while (*p == '-')
+		s = ++p;
+	while (*p)
+		if (*p++ == '/')
+			s = p;
+	if (*s == 'v') {
+		Verbose=1; ++s;
+	}
+	Progname = s;
+	if (s[0]=='r' && s[1]=='b')
+		Nozmodem = TRUE;
+	if (s[2] && s[0]=='r' && s[1]=='b')
+		Topipe=TRUE;
+	if (s[2] && s[0]=='r' && s[1]=='z')
+		Topipe=TRUE;
+    return 0;
+}
+
+/*
+ * Totalitarian Communist pathname processing
+ */
+int checkpath(char *name)
+{
+//	if (Restricted) {
+	//	if (fopen(name, "r") != NULL) {
+		//	canit();
+			//rt_kprintf(stderr, "\r\nrz: %s exists\n", name);
+		//	bibi();
+	//	}
+		/* restrict pathnames to current tree or uucppublic */
+	//	if ( substr(name, "../")
+		// || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
+		//	canit();
+			//rt_kprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
+		//	bibi();
+	//	}
+//	}
+     return 0;
+}
+
+/*
+ * Initialize for Zmodem receive attempt, try to activate Zmodem sender
+ *  Handles ZSINIT frame
+ *  Return ZFILE if Zmodem filename received, -1 on error,
+ *   ZCOMPL if transaction finished,  else 0
+ */
+int tryz(void)
+{
+	int n;
+	int cmdzack1flg;
+
+	if (Nozmodem)		/* Check for "rb" program name */
+		return 0;
+	Rxtimeout = 100;
+
+
+	for (n=5; --n>=0; ) {
+		/* Set buffer length (0) and capability flags */
+		stohdr(0L);
+		Txhdr[ZF0] = CANFDX|CANOVIO|CANBRK;
+		zshhdr(Badclose?ZFERR:ZRINIT, Txhdr);
+again:
+		switch (zgethdr(Rxhdr, 0)) {
+		case ZRQINIT:
+			continue;
+		case ZEOF:
+			continue;
+		case TIMEOUT:
+			continue;
+		case ZFILE:
+			zconv = Rxhdr[ZF0];
+			zmanag = Rxhdr[ZF1];
+			ztrans = Rxhdr[ZF2];
+			Badclose = FALSE;
+			if (zrbdata(secbuf, KSIZE) == GOTCRCW)
+				return ZFILE;
+			zshhdr(ZNAK, Txhdr);
+		case ZSINIT:
+			if (zrbdata(Attn, ZATTNLEN) == GOTCRCW) {
+				zshhdr(ZACK, Txhdr);
+				goto again;
+			}
+			zshhdr(ZNAK, Txhdr);
+			continue;
+		case ZFREECNT:
+			stohdr(getfree());
+			zshhdr(ZACK, Txhdr);
+			goto again;
+		case ZCOMMAND:
+			cmdzack1flg = Rxhdr[ZF0];
+			if (zrbdata(secbuf, KSIZE) == GOTCRCW) {
+				if (cmdzack1flg & ZCACK1)
+					stohdr(0L);
+				else
+					stohdr((long)sys2(secbuf));
+				purgeline();	/* dump impatient questions */
+				do {
+					zshhdr(ZCOMPL, Txhdr);
+				}
+				while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN);
+				ackbibi();
+				if (cmdzack1flg & ZCACK1)
+					exec2(secbuf);
+				return ZCOMPL;
+			}
+			zshhdr(ZNAK, Txhdr); goto again;
+		case ZCOMPL:
+			goto again;
+		default:
+			continue;
+		case ZFIN:
+			ackbibi(); return ZCOMPL;
+		case ZCAN:
+			return ERROR;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Receive 1 or more files with ZMODEM protocol
+ */
+int rzfiles(void)
+{
+	int c;
+
+	for (;;) {
+		switch (c = rzfile()) {
+		case ZEOF:
+		case ZSKIP:
+			switch (tryz()) {
+			case ZCOMPL:
+				return OK;
+			default:
+				return ERROR;
+			case ZFILE:
+				break;
+			}
+			continue;
+		default:
+			return c;
+		case ERROR:
+			return ERROR;
+		}
+	}
+}
+
+/*
+ * Receive a file with ZMODEM protocol
+ *  Assumes file name frame is in secbuf
+ */
+int rzfile(void)
+{
+	int c, n;
+	long int rxbytes;
+
+	Eofseen=FALSE;
+	if (procheader(secbuf) == ERROR) {
+		zshhdr(ZSKIP, Txhdr);
+		return ZSKIP;
+	}
+
+	n = 10; rxbytes = 0l;
+
+	for (;;) {
+		stohdr(rxbytes);
+		zshhdr(ZRPOS, Txhdr);
+nxthdr:
+		switch (c = zgethdr(Rxhdr, 0)) {
+		default:
+			vfile("rzfile: zgethdr returned %d", c);
+			return ERROR;
+		case ZNAK:
+		case TIMEOUT:
+			if ( --n < 0) {
+				vfile("rzfile: zgethdr returned %d", c);
+				return ERROR;
+			}
+		case ZFILE:
+			continue;
+		case ZEOF:
+			if (rclhdr(Rxhdr) != rxbytes) {
+				continue;
+			}
+			if (closeit()) {
+				Badclose = TRUE;
+				vfile("rzfile: closeit returned <> 0");
+				return ERROR;
+			}
+			vfile("rzfile: normal EOF");
+			return c;
+		case ERROR:	/* Too much garbage in header search error */
+			if ( --n < 0) {
+				vfile("rzfile: zgethdr returned %d", c);
+				return ERROR;
+			}
+			zmputs(Attn);
+			continue;
+		case ZDATA:
+			n = 10;
+			if (rclhdr(Rxhdr) != rxbytes) {
+				zmputs(Attn);
+				continue;
+			}
+moredata:
+			switch (c = zrbdata(secbuf, KSIZE)) {
+			case ZCAN:
+				vfile("rzfile: zgethdr returned %d", c);
+				return ERROR;
+			case ERROR:	/* CRC error */
+				if ( --n < 0) {
+					vfile("rzfile: zgethdr returned %d", c);
+					return ERROR;
+				}
+				zmputs(Attn);
+				continue;
+			case TIMEOUT:
+				if ( --n < 0) {
+					vfile("rzfile: zgethdr returned %d", c);
+					return ERROR;
+				}
+				continue;
+			case GOTCRCW:
+				putsec(secbuf, Rxcount);
+				rxbytes += Rxcount;
+				stohdr(rxbytes);
+				zshhdr(ZACK, Txhdr);
+				goto nxthdr;
+			case GOTCRCQ:
+				putsec(secbuf, Rxcount);
+				rxbytes += Rxcount;
+				stohdr(rxbytes);
+				zshhdr(ZACK, Txhdr);
+				goto moredata;
+			case GOTCRCG:
+				putsec(secbuf, Rxcount);
+				rxbytes += Rxcount;
+				goto moredata;
+			case GOTCRCE:
+				putsec(secbuf, Rxcount);
+				rxbytes += Rxcount;
+				goto nxthdr;
+			}
+		}
+	}
+}
+
+/*
+ * Send a string to the modem, processing for \336 (sleep 1 sec)
+ *   and \335 (break signal)
+ */
+int zmputs(char *s)
+{
+	int c;
+
+	while (*s) {
+		switch (c = *s++) {
+		case '\336':
+			//sleep(1); 
+			continue;
+		case '\335':
+			sendbrk(); continue;
+		default:
+			sendline(c);
+		}
+	}
+	return 0;
+}
+
+/*
+ * Close the receive dataset, return OK or ERROR
+ */
+int closeit(void)
+{
+	if (Topipe) {
+		if (close(fout)) {
+			return ERROR;
+		}
+		return OK;
+	}
+	if (close(fout)==ERROR) {
+		//rt_kprintf(stderr, "file close ERROR\n");
+		return ERROR;
+	}
+//	if (Modtime) {
+//		timep[0] = time(NULL);
+	//	timep[1] = Modtime;
+	//	utime(Pathname, timep);
+	//}
+	//if (Filemode)
+		//chmod(Pathname, (07777 & Filemode));
+	return OK;
+}
+
+/*
+ * Ack a ZFIN packet, let byegones be byegones
+ */
+int ackbibi(void)
+{
+	int n;
+
+	vfile("ackbibi:");
+	Readnum = 1;
+	stohdr(0L);
+	for (n=4; --n>=0; ) {
+		zshhdr(ZFIN, Txhdr);
+		for (;;) {
+			switch (readline(100)) {
+			case 'O':
+				readline(1);	/* Discard 2nd 'O' */
+				/* ***** FALL THRU TO ***** */
+			case TIMEOUT:
+				vfile("ackbibi complete");
+				return 0;
+			default:
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * Local console output simulation
+ */
+int bttyout(int c)
+{
+	//if (Verbose || fromcu)
+		//putc(c, stderr);
+	return 0;
+}
+
+/*
+ * Strip leading ! if present, do shell escape. 
+ */
+int sys2(char *s)
+{
+	if (*s == '!')
+		++s;
+	return 0;
+}
+/*
+ * Strip leading ! if present, do exec.
+ */
+int exec2(char *s)
+{
+	if (*s == '!')
+		++s;
+	mode(0);
+	return 0;
+}

+ 77 - 0
components/utilities/ZMODEM/RZ.H

@@ -0,0 +1,77 @@
+#ifndef __RZ_H__
+#define __RZ_H__
+
+#include "zmodem.h"
+
+
+unsigned short int updcrc(int c, unsigned int crc);
+void zmputs(char *s);
+int closeit(void);
+int sys2(char *s);
+int exec2(char *s);
+int rzfile(void);
+void ackbibi(void);
+unsigned int IsAnyLower(char *s);
+void usage(void);
+static int wcrx(void);
+char *substr(char *s, char *t);
+
+void alrm(void);
+void bibi(int n);
+int zreceive_main(void);
+void usage(void);
+static int wcreceive(unsigned int argc, char **argp);
+static int wcrxpn(char *rpn);
+static int wcgetsec(char *rxbuf, int maxtime);
+int readline(int timeout);
+unsigned short int updcrc(int c, unsigned int crc);
+int procheader(char *name);
+int purgeline(void);
+int putsec(char *buf, int n);  
+int readline(int timeout);
+unsigned short int updcrc(int c, unsigned int crc);
+
+int bttyout(int c);
+int sys2(char *s);
+int exec2(char *s);
+void sendline(char c);
+void xsendline(char c);
+void canit(void);
+int tryz(void);
+int rzfiles(void);
+
+
+extern int Verbose;
+extern int iofd;		/* File descriptor for ioctls & reads */
+extern int Zmodem;		/* ZMODEM protocol requested */
+extern int Nozmodem;	/* If invoked as "rb" */
+/* Ward Christensen / CP/M parameters - Don't change these! */
+#define ENQ 005
+#define CAN ('X'&037)
+//#define XOFF ('s'&037)
+//#define XON ('q'&037)
+#define SOH 1
+#define STX 2
+#define EOT 4
+#define ACK 6
+#define NAK 025
+#define CPMEOF 032
+#define WANTCRC 0103	/* send C not NAK to get crc not checksum */
+#define TIMEOUT (-2)
+#define ERRORMAX 5
+#define RETRYMAX 5
+#define WCEOT (-10)
+#define SECSIZ 128	/* cp/m's Magic Number record size */
+#define PATHLEN 257	/* ready for 4.2 bsd ? */
+#define KSIZE 1024	/* record size with k option */
+#define UNIXFILE 0x8000	/* happens to the the S_IFREG file mask bit for stat */
+/**************************zm.c **************************/
+
+
+
+
+
+
+
+
+#endif

+ 336 - 0
components/utilities/ZMODEM/SZ.1

@@ -0,0 +1,336 @@
+'\" Revision Level 
+'\" Last Delta     5-19-86
+.TH SZ 1 OMEN
+.SH NAME
+sz \- XMODEM, YMODEM, ZMODEM Batch file Send
+.SH SYNOPSIS
+sz
+.RB [\- +1adfknqTuvy ]
+.I file ...
+.br
+sz -X
+.RB [\- 1kquv ]
+.I file
+.br
+sz
+.RB [\- 1qv ]
+.B "-c COMMAND"
+.br
+sz
+.RB [\- 1qv ]
+.B "-i COMMAND"
+.SH DESCRIPTION
+.B Sz
+uses the ZMODEM, YMODEM or XMODEM error correcting protocol to send
+one or more files over a serial port to a variety of programs running under
+PC-DOS, CP/M, Unix, VMS, and other operating systems.
+
+
+The first form of
+.B sz
+sends one or more files with ZMODEM or YMODEM batch protocol.
+Normally, only the file name part of the pathname is transmitted.
+On
+.SM Unix
+systems, additional information about the file is transmitted.
+If the receiving program uses this information,
+the transmitted file length controls the exact number of bytes written to
+the output dataset,
+and the modify time and file mode
+are set accordingly.
+
+Output from another program may be piped to
+.B sz
+for transmission by specifying the
+.B -1
+option and denoting standard input by "-":
+.ce
+ps -ef | sz -
+The program output is transmitted with the filename sPID.sz
+where PID is the process ID of the
+.B sz
+program.
+If the environment variable
+.B ONAME
+is set, that is used instead.
+In this case, the Unix command:
+.ce
+ONAME=con ps -ef|sz -ay -
+will send a "file" to the PC-DOS console display.
+The
+.B -y
+bypasses the receiver\'s checking of the output filename.
+The
+.B -a
+causes the receiver to convert Unix newlines to PC-DOS carriage returns
+and linefeeds.
+
+Unix
+.B sz
+supports
+.B YMODEM-g
+with "cbreak" tty mode, XON/XOFF flow control,
+and the interrupt character set to CAN.
+.B YMODEM-g
+(Professional-YAM
+.B g
+option)
+increases throughput over error free channels
+(direct connection, X.PC, etc.)
+by not acknowledging each transmitted sector.
+
+
+The second form of
+.B sz
+uses the
+.B -X
+flag to send a single
+.I file
+with
+.B XMODEM
+protocol.
+The user must supply the file name to both sending and receiving programs.
+
+Iff
+.B sz
+is invoked with $SHELL set and iff that variable contains the
+string
+.I "rsh"
+or
+.I "rksh"
+(restricted shell), sz operates in restricted mode.
+Restricted mode restricts pathnames to the current directory and
+PUBDIR (usually /usr/spool/uucppublic) and/or subdirectories
+thereof.
+
+
+The third form sends a single COMMAND to the receiver for execution.
+.B Sz
+exits with the COMMAND return value.
+If COMMAND includes spaces or characters special to the shell,
+it must be quoted.
+
+The fourth form sends a single COMMAND to the receiver for execution.
+.B Sz
+exits as soon as the receiver has received the command, before it is executed.
+
+
+If sz is invoked with stdout and stderr to different datasets,
+Verbose is set to 2, causing frame by frame progress reports
+to stderr.
+This may be disabled with the
+.B q
+option.
+.PP
+The meanings of the available options are:
+.PP
+.PD 0
+.TP
+.B +
+Force the receiver to append transmitted data to an existing file
+(ZMODEM only).
+.TP
+.B 1
+Use file descriptor 1 for ioctls and reads (Unix only).
+By default, file descriptor 0 is used.
+This option allows
+.B sz
+to be used with the
+.I cu
+~$
+command.
+.TP
+.B a
+Convert NL characters in the transmitted file to CR/LF.
+This is done by the sender for XMODEM and YMODEM, by the receiver
+for ZMODEM.
+.TP
+.B "c COMMAND"
+Send COMMAND to the receiver for execution, return with COMMAND\'s exit status.
+.TP
+.B "C N"
+Make N attempts at ten second intervals
+to read COMMAND\'s exit status before exiting.
+.TP
+.B d
+Change all instances of "." to "/" in the transmitted pathname.
+Thus, C.omenB0000 (which is unacceptable to MSDOS or CP/M)
+is transmitted as C/omenB0000.
+If the resultant filename has more than 8 characters in the stem,
+a "." in inserted to allow a total of eleven.
+.TP
+.B f
+Send Full pathname.
+Normally directory prefixes are stripped from the transmitted
+filename.
+.TP
+.B "i COMMAND"
+Send COMMAND to the receiver for execution, return Immediately.
+.TP
+.B k
+Send files using YMODEM 1024 byte blocks
+rather than the default 128 byte blocks.
+1024 byte packets speed file transfers at high bit rates.
+(ZMODEM streams the data for the best possible throughput.)
+.TP
+.B n
+Instruct ZMODEM receiver to skip files if the length and modification times
+of the source file and the file on the destination system are equal.
+.TP
+.B N
+Instruct ZMODEM receiver to skip files if the length and CRC\'s
+of the source file and the file on the destination system are equal.
+.TP
+.B q
+Quiet suppresses verbosity.
+.TP
+.B r
+Resume interrupted file transfer.
+If the source file is longer than the destination file,
+the transfer commences at the offset in the source file that equals
+the length of the destination file.
+.TP
+.B u
+Unlink the file after successful transmission.
+.TP
+.B v
+Verbose
+causes a list of file
+names to be appended to
+/tmp/szlog .
+More v's generate more output.
+.TP
+.B X
+Send a single file with
+.B XMODEM
+protocol.
+.TP
+.B y
+Force a ZMODEM receiving program to overwrite any existing file
+with the same name.
+.PD
+.SH EXAMPLES
+.ne 7
+.B "ZMODEM File Transfer"
+.br
+.B "$ sz -a *.c"
+.br
+This single command transfers all .c files in the current Unix directory
+with conversion
+.RB ( -a )
+to PC-DOS end of line conventions.
+With ZMODEM AutoDownload enabled, Professional-YAM automatically recieves
+the files after performing a security challenge.
+
+.B "ZMODEM Command Download"
+.br
+ cpszall:all
+    sz -c "c:;cd /yam/dist"
+    sz -ya $(YD)/*.me
+    sz -yqb y*.exe
+    sz -c "cd /yam"
+    sz -i "!insms"
+.br
+This Makefile fragment uses
+.B sz
+to issue commands to Professional-YAM to change current disk and directory.
+Next,
+.B sz
+transfers the
+.I .me
+files from the $YD directory, commanding the receiver to overwrite the old files
+and to convert from Unix end of line conventions to PC-DOS conventions.
+The third line transfers some
+.I .exe
+files.
+The fourth and fifth lines command Pro-YAM to
+change directory and execute a PC-DOS batch file
+.I insms .
+Since the batch file takes considerable time, the
+.B "-i"
+form is used to allow
+.B sz
+to exit immediately.
+
+.B "XMODEM File Transfer"
+.br
+$
+.B "sz -Xa foo.c"
+.br
+.B "ESC"
+.br
+.B "rx foo.c"
+.br
+The above three commands transfer a single file
+from Unix to a PC and Crosstalk XVI 3.6,
+translating Unix newlines to DOS CR/LF.
+
+.SH SEE ALSO
+rz(omen),
+ZMODEM.DOC,
+YMODEM.DOC,
+Professional-YAM manual,
+IMP(CP/M),
+cu(1),
+sq(omen),
+todos(omen),
+tocpm(omen),
+tomac(omen),
+yam(omen)
+
+Compile time options required for various operating systems are described in
+the source file.
+.SH "VMS VERSION"
+The VMS version does not transmit the file date.
+The VMS version calculates the file length by reading the file
+and counting the bytes.
+
+The VMS version does not support YMODEM-g or ZMODEM.
+
+When VMS is lightly loaded, the response time may be too quick for MODEM7
+unless the MODEM7
+.B "q"
+modifier is used.
+
+The VMS C standard i/o package and RMS sometimes interact to modify
+file contents unexpectedly.
+.SH FILES
+sz.c, rbsb.c, zm.c, zmodem.h source files
+
+/tmp/szlog stores debugging output (sz -vv)
+.SH "TESTING FEATURE"
+The command "sz -T file"
+exercises the
+.B Attn
+sequence error recovery by commanding
+errors with unterminated packets.
+The receiving program should complain five times about
+binary data packets being too long.
+Each time
+.B sz
+is interrupted,
+it should send a ZDATA header followed by another defective packet.
+If the receiver does not detect five long data packets,
+the
+.B Attn
+sequence is not interrupting the sender, and the
+.B Myattn
+string in
+.B sz.c
+must be modified.
+
+After 5 packets,
+.B sz
+stops the "transfer" and
+prints the total number of characters "sent" (Tcount).
+The difference between Tcount and 5120 represents the number of characters
+stored in various buffers when the Attn sequence is generated.
+.SH BUGS
+XMODEM transfers add up to 127 spurious bytes per file.
+
+Circular buffering and a ZMODEM sliding window should be used
+when input is from pipes instead of acknowledging frames each 1024 bytes.
+.B Sz
+should check for the presence of at least one accessible file before
+getting hot and bothered.
+The test mode leaves a zero length file on the receiving system.

+ 1168 - 0
components/utilities/ZMODEM/SZ.C

@@ -0,0 +1,1168 @@
+#define VERSION "sz 1.03 05-18-86"
+#define PUBDIR "/usr/spool/uucppublic"
+
+/*% cc -O -K sz.c -o sz; size sz
+
+ * sz.c By Chuck Forsberg
+ *
+ *	cc -O sz.c -o sz		USG (SYS III/V) Unix
+ * 	cc -O -DV7  sz.c -o sz		Unix Version 7, 2.8 - 4.3 BSD
+ *
+ *  ******* Some systems (Venix, Coherent, Regulus) do not *******
+ *  ******* support tty raw mode read(2) identically to    *******
+ *  ******* Unix. ONEREAD must be defined to force one     *******
+ *  ******* character reads for these systems.		   *******
+ *
+ * A program for Unix to send files and commands to computers running
+ *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
+ *
+ *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
+ *
+ *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
+ */
+
+/*
+ * Attention string to be executed by receiver to interrupt streaming data
+ *  when an error is detected.  A pause (0336) may be needed before the
+ *  ^C (03) or after it.
+ */
+char Myattn[] = { 03, 0336, 0 };
+
+unsigned updcrc();
+char *substr(), *getenv();
+
+#define LOGFILE "/tmp/szlog"
+#define zperr vfile
+
+/*
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+*/
+#include "rtthread.h"
+#include "finsh.h"
+#include "shell.h"	
+#include"rtdef.h"
+#include <dfs.h>
+#include <dfs_file.h>
+#include <dfs_posix.h>
+#include "zmodem.h"
+
+#define PATHLEN 256
+#define OK 0
+#define FALSE 0
+#define TRUE 1
+#define ERROR (-1)
+
+#define HOWMANY 2
+int Zmodem=0;		/* ZMODEM protocol requested */
+unsigned Baudrate;
+#include "rbsb.c"	/* most of the system dependent stuff here */
+
+int in;
+
+/* Ward Christensen / CP/M parameters - Don't change these! */
+#define ENQ 005
+#define CAN ('X'&037)
+#define XOFF ('s'&037)
+#define XON ('q'&037)
+#define SOH 1
+#define STX 2
+#define EOT 4
+#define ACK 6
+#define NAK 025
+#define CPMEOF 032
+#define WANTCRC 0103	/* send C not NAK to get crc not checksum */
+#define WANTG 0107	/* Send G not NAK to get nonstop batch xmsn */
+#define TIMEOUT (-2)
+#define RETRYMAX 10
+#define SECSIZ 128	/* cp/m's Magic Number record size */
+#define KSIZE 1024
+
+char Lastrx;
+char Crcflg;
+int Wcsmask=0377;
+int Verbose=0;
+int Modem=0;		/* MODEM - don't send pathnames */
+int Restricted=0;	/* restricted; no /.. or ../ in filenames */
+int Quiet=0;		/* overrides logic that would otherwise set verbose */
+int Ascii=0;		/* Add CR's for brain damaged programs */
+int Fullname=0;		/* transmit full pathname */
+int Unlinkafter=0;	/* Unlink file after it is sent */
+int Dottoslash=0;	/* Change foo.bar.baz to foo/bar/baz */
+int firstsec;
+int errcnt=0;		/* number of files unreadable */
+int blklen=SECSIZ;		/* length of transmitted records */
+int Optiong;		/* Let it rip no wait for sector ACK's */
+int Noeofseen;
+int Totsecs;		/* total number of sectors this file */
+char txbuf[KSIZE];
+int Filcnt=0;		/* count of number of files opened */
+int Lfseen=0;
+unsigned Rxbuflen = 16384;	/* Receiver's max buffer length */
+int Rxflags = 0;
+char Lzconv;	/* Local ZMODEM file conversion request */
+char Lzmanag;	/* Local ZMODEM file management request */
+char Lztrans;
+char zconv;		/* ZMODEM file conversion request */
+char zmanag;		/* ZMODEM file management request */
+char ztrans;		/* ZMODEM file transport request */
+int Command;		/* Send a command, then exit. */
+char *Cmdstr;		/* Pointer to the command string */
+int Cmdtries = 11;
+int Cmdack1;		/* Rx ACKs command, then do it */
+int Exitcode;
+int Testattn;		/* Force receiver to send Attn, etc with qbf. */
+char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
+
+
+//jmp_buf tohere;		/* For the interrupt on RX timeout */
+//jmp_buf intrjmp;	/* For the interrupt on RX CAN */
+
+/* called by signal interrupt or terminate to clean things up */
+bibi(n)
+{
+	canit(); 
+	//fflush(stdout); 
+	mode(0);
+	//rt_kprintf(stderr, "sz: caught signal %d; exiting\n", n);
+    //if (n == SIGQUIT)
+	//	abort();
+	//exit(128+n);
+}
+/* Called when Zmodem gets an interrupt (^X) */
+onintr()
+{
+	//signal(SIGINT, SIG_IGN);
+	//longjmp(intrjmp, -1);
+}
+
+
+//#define sendline(c) putchar(c & Wcsmask)
+
+//#define xsendline(c) putchar(c)
+int sendline (int c)
+{
+	c = c&Wcsmask;
+	zwrite(c);
+
+}
+int xsendline(int c)
+{
+     zwrite(c);
+}
+
+
+flushmo()
+{
+	//fflush(stdout);
+}
+
+#include "zm.c"
+
+zsmain(argc, argv)
+char *argv[];
+{
+	register char *cp;
+	register npats;
+	int agcnt; char **agcv;
+	char **patts;
+	static char xXbuf[BUFSIZ];
+
+	//if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh")))
+	//	Restricted=TRUE;
+
+	Rxtimeout = 600;
+	npats=0;
+	/*
+	if (argc<2)
+		usage();
+	//setbuf(stdout, xXbuf);		
+	while (--argc) {
+		cp = *++argv;
+		if (*cp++ == '-' && *cp) {
+			while ( *cp) {
+				switch(*cp++) {
+				case '+':
+					Lzmanag = ZMAPND; break;
+				case '1':
+					iofd = 1; break;
+				case '7':
+					Wcsmask=0177; break;
+				case 'a':
+					Lzconv = ZCNL;
+					Ascii = TRUE; break;
+				case 'b':
+					Lzconv = ZCBIN; break;
+				case 'C':
+					if (--argc < 1) {
+						usage();
+					}
+					Cmdtries = atoi(*++argv);
+					break;
+				case 'i':
+					Cmdack1 = ZCACK1;
+					//* **** FALL THROUGH TO ****  
+				case 'c':
+					if (--argc != 1) {
+						usage();
+					}
+					Command = TRUE;
+					Cmdstr = *++argv;
+					break;
+				case 'd':
+					++Dottoslash;
+					//* **** FALL THROUGH TO **** * 
+				case 'f':
+					Fullname=TRUE; break;
+				case 'k':
+					blklen=KSIZE; break;
+				case 'N':
+					Lzmanag = ZMCRC;  break;
+				case 'n':
+					Lzmanag = ZMNEW;  break;
+				case 'r':
+					Lzconv = ZCRESUM;
+				case 'q':
+					Quiet=TRUE; Verbose=0; break;
+				case 'T':
+					Testattn = TRUE; break;
+				case 'u':
+					++Unlinkafter; break;
+				case 'v':
+					++Verbose; break;
+				case 'X':
+					++Modem; break;
+				case 'y':
+					Lzmanag = ZMCLOB; break;
+				default:
+					usage();
+				}
+			}
+		}
+		else if ( !npats && argc>0) {
+			if (argv[0][0]) {
+				npats=argc;
+				patts=argv;
+				if ( !strcmp(*patts, "-"))
+					iofd = 1;
+			}
+		}
+	}
+	if (npats < 1 && !Command) 
+		usage();
+	if (Verbose) {
+		if (freopen(LOGFILE, "a", stderr)==NULL) {
+			printf("Can't open log file %s\n",LOGFILE);
+			exit(0200);
+		}
+		setbuf(stderr, NULL);
+	}
+	if (fromcu() && !Quiet) {
+		if (Verbose == 0)
+			Verbose = 2;
+	}
+
+	mode(1);
+
+//	if (signal(SIGINT, bibi) == SIG_IGN) {
+//		signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
+//	}
+//	else {
+	//	signal(SIGINT, bibi); signal(SIGKILL, bibi);
+//		signal(SIGQUIT, bibi);
+//	}
+
+	if ( !Modem) {
+		if (!Command) {
+			printf("rz\r");  fflush(stdout);
+		}
+		if (!Command && !Quiet && Verbose != 1) {
+			rt_kprintf(stderr, "sz: %d file%s requested:\r\n",
+			 npats, npats>1?"s":"");
+			for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
+				rt_kprintf(stderr, "%s ", *agcv++);
+			}
+			rt_kprintf(stderr, "\r\n");
+			printf("\r\n\bSending in Batch Mode\r\n");
+		}
+		stohdr(0L);
+		if (Command)
+			Txhdr[ZF0] = ZCOMMAND;
+		zshhdr(ZRQINIT, Txhdr);
+	}
+	fflush(stdout);
+	*/
+	if (Command) {
+		if (getzrxinit()) {
+			Exitcode=0200; canit();
+		}
+		else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
+			Exitcode=0200; canit();
+		}
+	} else if (wcsend(npats, patts)==ERROR) {
+		Exitcode=0200;
+		canit();
+	}
+	//fflush(stdout);
+	//mode(0);
+	//exit((errcnt != 0) | Exitcode);
+	/*NOTREACHED*/
+}
+
+wcsend(argc, argp)
+char *argp[];
+{
+	register n;
+
+	Crcflg=FALSE;
+	firstsec=TRUE;
+	//for (n=0; n<argc; ++n) {
+		Totsecs = 0;
+		if (wcs(argp[n])==ERROR)
+			return ERROR;
+	//}
+	Totsecs = 0;
+	if (Filcnt==0) {	/* bitch if we couldn't open ANY files */
+		//rt_kprintf(stderr,"\r\nCan't open any requested files.\r\n");
+		return ERROR;
+	}
+	if (Zmodem)
+		saybibi();
+	else
+		wctxpn("");
+	return OK;
+}
+
+wcs(oname)
+char *oname;
+{
+	register c;
+	register char *p;
+	struct stat f;
+	char name[PATHLEN];
+	 char *filename ="/tt2.txt";
+	 oname = filename;
+	strcpy(name, oname);
+
+	if (Restricted) {
+		/* restrict pathnames to current tree or uucppublic */
+		if ( substr(name, "../")
+		 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
+			canit();
+			//rt_kprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
+			return ERROR;
+		}
+	}
+
+	//if ( !strcmp(oname, "-")) {
+	//	if ((p = getenv("ONAME")) && *p)
+		//	strcpy(name, p);
+		//else
+			//sprintf(name, "s%d.sz", getpid());
+/////////////////////////////////////////////////////////////////////////////////////////////////
+		//in = stdin;
+//	}
+	//else if ((in=fopen(oname, "r"))==NULL) {
+	//	++errcnt;
+		//return OK;	/* pass over it, there may be others */
+	//}
+	if ((in=open(oname, DFS_O_RDONLY,0)) <0)
+	{
+	    ++errcnt;
+	    return OK;
+	}
+	++Noeofseen;
+	/* Check for directory or block special files */
+	fstat(in, &f);
+	c = f.st_mode & S_IFMT;
+	if (c == S_IFDIR || c == S_IFBLK) {
+		close(in);
+		return OK;
+	}
+
+	++Filcnt;
+	switch (wctxpn(name)) {
+	case ERROR:
+		return ERROR;
+	case ZSKIP:
+		return OK;
+	}
+	if (!Zmodem && wctx()==ERROR)
+		return ERROR;
+	if (Unlinkafter)
+		unlink(oname);
+	return 0;
+}
+
+/*
+ * generate and transmit pathname block consisting of
+ *  pathname (null terminated),
+ *  file length, mode time and file mode in octal
+ *  as provided by the Unix fstat call.
+ *  N.B.: modifies the passed name, may extend it!
+ */
+wctxpn(name)
+char *name;
+{
+	register char *p, *q;
+	char name2[PATHLEN];
+	struct stat f;
+
+	if (Modem) {
+		//if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
+		//	rt_kprintf(stderr, "Sending %s, %ld blocks: ",
+			 // name, f.st_size>>7);
+		//}
+		//rt_kprintf(stderr, "Give your local XMODEM receive command now.\r\n");
+		return OK;
+	}
+	logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
+	if ( !Zmodem)
+		if (getnak())
+			return ERROR;
+
+	q = (char *) 0;
+	if (Dottoslash) {		/* change . to . */
+		for (p=name; *p; ++p) {
+			if (*p == '/')
+				q = p;
+			else if (*p == '.')
+				*(q=p) = '/';
+		}
+		if (q && strlen(++q) > 8) {	/* If name>8 chars */
+			q += 8;			/*   make it .ext */
+			strcpy(name2, q);	/* save excess of name */
+			*q = '.';
+			strcpy(++q, name2);	/* add it back */
+		}
+	}
+
+	for (p=name, q=txbuf ; *p; )
+		if ((*q++ = *p++) == '/' && !Fullname)
+			q = txbuf;
+	*q++ = 0;
+	p=q;
+	while (q < (txbuf + KSIZE))
+		*q++ = 0;
+	//if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
+		//sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
+	fstat(in,&f);
+	/* force 1k blocks if name won't fit in 128 byte block */
+	if (txbuf[125])
+		blklen=KSIZE;
+	else {		/* A little goodie for IMP/KMD */
+		if (Zmodem)
+			blklen = SECSIZ;
+		txbuf[127] = f.st_size >>7;
+		txbuf[126] = f.st_size >>15;
+	}
+	if (Zmodem)
+		return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
+	if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
+		return ERROR;
+	return OK;
+}
+
+getnak()
+{
+	register firstch;
+
+	Lastrx = 0;
+	for (;;) {
+		switch (firstch = readock(800,1)) {
+		case ZPAD:
+			if (getzrxinit())
+				return ERROR;
+			Ascii = 0;
+			return FALSE;
+		case TIMEOUT:
+			logent("Timeout on pathname\n");
+			return TRUE;
+		case WANTG:
+			mode(2);	/* Set cbreak, XON/XOFF, etc. */
+			Optiong = TRUE;
+			blklen=KSIZE;
+		case WANTCRC:
+			Crcflg = TRUE;
+		case NAK:
+			return FALSE;
+		case CAN:
+			if (Lastrx == CAN)
+				return TRUE;
+		default:
+			break;
+		}
+		Lastrx = firstch;
+	}
+}
+
+
+wctx()
+{
+	register int sectnum, attempts, firstch;
+
+	firstsec=TRUE;
+
+	while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC
+	  && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
+		;
+	if (firstch==CAN) {
+		logent("Receiver CANcelled\n");
+		return ERROR;
+	}
+	if (firstch==WANTCRC)
+		Crcflg=TRUE;
+	if (firstch==WANTG)
+		Crcflg=TRUE;
+	sectnum=1;
+	while (filbuf(txbuf, blklen)) {
+		if (wcputsec(txbuf, sectnum, blklen)==ERROR) {
+			return ERROR;
+		} else
+			sectnum++;
+	}
+	//if (Verbose>1)
+	//	rt_kprintf(stderr, " Closing ");
+	close(in);
+	attempts=0;
+	do {
+		logent(" EOT ");
+		purgeline();
+		sendline(EOT);
+		//fflush(stdout);
+		++attempts;
+	}
+		while ((firstch=(readock(100, 1)) != ACK) && attempts < RETRYMAX);
+	if (attempts == RETRYMAX) {
+		logent("No ACK on EOT\n");
+		return ERROR;
+	}
+	else
+		return OK;
+}
+
+wcputsec(buf, sectnum, cseclen)
+char *buf;
+int sectnum;
+int cseclen;	/* data length of this sector to send */
+{
+	register checksum, wcj;
+	register char *cp;
+	unsigned oldcrc;
+	int firstch;
+	int attempts;
+
+	firstch=0;	/* part of logic to detect CAN CAN */
+
+	//if (Verbose>1)
+	//	rt_kprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
+	for (attempts=0; attempts <= RETRYMAX; attempts++) {
+		Lastrx= firstch;
+		sendline(cseclen==KSIZE?STX:SOH);
+		sendline(sectnum);
+		sendline(-sectnum -1);
+		oldcrc=checksum=0;
+		for (wcj=cseclen,cp=buf; --wcj>=0; ) {
+			sendline(*cp);
+			oldcrc=updcrc(*cp, oldcrc);
+			checksum += *cp++;
+		}
+		if (Crcflg) {
+			oldcrc=updcrc(0,updcrc(0,oldcrc));
+			sendline((int)oldcrc>>8);
+			sendline((int)oldcrc);
+		}
+		else
+			sendline(checksum);
+
+		if (Optiong) {
+			firstsec = FALSE; return OK;
+		}
+		firstch = readock(400, (Noeofseen&&sectnum) ? 2:1);
+gotnak:
+		switch (firstch) {
+		case CAN:
+			if(Lastrx == CAN) {
+cancan:
+				logent("Cancelled\n");  return ERROR;
+			}
+			break;
+		case TIMEOUT:
+			logent("Timeout on sector ACK\n"); continue;
+		case WANTCRC:
+			if (firstsec)
+				Crcflg = TRUE;
+		case NAK:
+			logent("NAK on sector\n"); continue;
+		case ACK: 
+			firstsec=FALSE;
+			Totsecs += (cseclen>>7);
+			return OK;
+		case ERROR:
+			logent("Got burst for sector ACK\n"); break;
+		default:
+			logent("Got %02x for sector ACK\n", firstch); break;
+		}
+		for (;;) {
+			Lastrx = firstch;
+			if ((firstch = readock(400, 2)) == TIMEOUT)
+				break;
+			if (firstch == NAK || firstch == WANTCRC)
+				goto gotnak;
+			if (firstch == CAN && Lastrx == CAN)
+				goto cancan;
+		}
+	}
+	logent("Retry Count Exceeded\n");
+	return ERROR;
+}
+
+/* fill buf with count chars padding with ^Z for CPM */
+filbuf(buf, count)
+register char *buf;
+{
+	register c, m;
+
+	if ( !Ascii) {
+		m = read(in, buf, count);
+		if (m <= 0)
+			return 0;
+		while (m < count)
+			buf[m++] = 032;
+		return count;
+	}
+	m=count;
+	if (Lfseen) {
+		*buf++ = 012; --m; Lfseen = 0;
+	}
+	/////////////////////////////////////////////////////////////////////////////////////
+	/*
+	while ((c=getc(in))!=EOF) {
+		if (c == 012) {
+			*buf++ = 015;
+			if (--m == 0) {
+				Lfseen = TRUE; break;
+			}
+		}
+		*buf++ =c;
+		if (--m == 0)
+			break;
+	}
+	*/
+	if (m==count)
+		return 0;
+	else
+		while (--m>=0)
+			*buf++ = CPMEOF;
+	return count;
+}
+/* fill buf with count chars */
+zfilbuf(buf, count)
+register char *buf;
+{  //int read(int fd, void *buf, size_t len)
+	int c, m;
+	int res;
+
+	m=count;
+	res = 0;
+	while (1) {
+	    res = read(in,&c,1);
+		if (res == 0) break;
+		*buf++ =c;
+		res = 0;
+		if (--m == 0)
+			break;
+	}
+	return (count - m);
+}
+
+/* VARARGS1 */
+vfile(f, a, b, c)
+register char *f;
+{
+//	if (Verbose > 1) {
+	//	rt_kprintf(stderr, f, a, b, c);
+	//	rt_kprintf(stderr, "\n");
+//	}
+}
+
+
+alarm()
+{
+	//longjmp(tohere, -1);
+}
+
+
+/*
+ * readock(timeout, count) reads character(s) from file descriptor 0
+ *  (1 <= count <= 3)
+ * it attempts to read count characters. If it gets more than one,
+ * it is an error unless all are CAN
+ * (otherwise, only normal response is ACK, CAN, or C)
+ *  Only looks for one if Optiong, which signifies cbreak, not raw input
+ *
+ * timeout is in tenths of seconds
+ */
+readock(timeout, count)
+{
+	register int c;
+	static char byt[5];
+	int ch;
+	if (Optiong)
+		count = 1;	/* Special hack for cbreak */
+
+	//fflush(stdout);
+	//if (setjmp(tohere)) {
+	//	logent("TIMEOUT\n");
+	//	return TIMEOUT;
+	//}
+    c = 0;
+	while (1)
+	{
+     	  c = zread(shell->device, 0, byt, 1);
+          if (c > 0) break;
+	}
+	//if (Verbose>5)
+	//	rt_kprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
+	if (c<1)
+		return TIMEOUT;
+	if (c==1)
+		return (byt[0]&0377);
+	else
+		while (c)
+			if (byt[--c] != CAN)
+				return ERROR;
+	return CAN;
+}
+readline(n)
+{
+	return (readock(n, 1));
+}
+
+
+purgeline()
+{
+#ifdef USG
+	ioctl(iofd, TCFLSH, 0);
+#else
+	lseek(iofd, 0L, 2);
+#endif
+}
+
+/* update CRC */
+unsigned
+updcrc(c, crc)
+register c;
+register unsigned crc;
+{
+	register count;
+
+	for (count=8; --count>=0;) {
+		if (crc & 0x8000) {
+			crc <<= 1;
+			crc += (((c<<=1) & 0400)  !=  0);
+			crc ^= 0x1021;
+		}
+		else {
+			crc <<= 1;
+			crc += (((c<<=1) & 0400)  !=  0);
+		}
+	}
+	return crc;	
+}
+
+/* send cancel string to get the other end to shut up */
+canit()
+{
+	static char canistr[] = {
+	 ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
+	};
+
+	//printf(canistr);
+	//fflush(stdout);
+}
+
+/*VARARGS1*/
+logent(a, b, c)
+char *a, *b, *c;
+{
+//	if(Verbose)
+	//	rt_kprintf(stderr, a, b, c);
+}
+
+/*
+ * return 1 iff stdout and stderr are different devices
+ *  indicating this program operating with a modem on a
+ *  different line
+ */
+fromcu()
+{
+	struct stat a, b;
+	fstat(1, &a); fstat(2, &b);
+//	return (a.st_rdev != b.st_rdev);
+}
+
+/*
+ * substr(string, token) searches for token in string s
+ * returns pointer to token within string if found, NULL otherwise
+ */
+char *
+substr(s, t)
+register char *s,*t;
+{
+	register char *ss,*tt;
+	/* search for first char of token */
+	for (ss=s; *s; s++)
+		if (*s == *t)
+			/* compare token with substring */
+			for (ss=s,tt=t; ;) {
+				if (*tt == 0)
+					return s;
+				if (*ss++ != *tt++)
+					break;
+			}
+	return NULL;
+}
+
+usage()
+{
+
+}
+
+/*
+ * Get the receiver's init parameters
+ */
+getzrxinit()
+{
+	register n;
+	struct stat f;
+
+	for (n=10; --n>=0; ) {
+		
+		switch (zgethdr(Rxhdr, 1)) {
+		case ZCHALLENGE:	/* Echo receiver's challenge numbr */
+			stohdr(Rxpos);
+			zshhdr(ZACK, Txhdr);
+			continue;
+		case ZCOMMAND:		/* They didn't see out ZRQINIT */
+			stohdr(0L);
+			zshhdr(ZRQINIT, Txhdr);
+			continue;
+		case ZRINIT:
+			Rxflags = Rxhdr[ZF0];
+			Rxbuflen = Rxhdr[ZP0] + (Rxhdr[ZP1]<<8);
+			//signal(SIGINT, SIG_IGN);
+			mode(2);	/* Set cbreak, XON/XOFF, etc. */
+
+			/* If using a pipe for testing set lower buf len */
+			fstat(iofd, &f);
+			if ((f.st_mode & S_IFMT) != S_IFCHR
+			  && (Rxbuflen == 0 || Rxbuflen > 4096))
+				Rxbuflen = 4096;
+			/*
+			 * If input is not a regular file, force ACK's each 1024
+			 *  (A smarter strategey could be used here ...)
+			 */
+			fstat(in, &f);
+			if (((f.st_mode & S_IFMT) != S_IFREG)
+			  && (Rxbuflen == 0 || Rxbuflen > 1024))
+				Rxbuflen = 1024;
+
+			return (sendzsinit());
+		case ZCAN:
+		case TIMEOUT:
+			return ERROR;
+		case ZRQINIT:
+			if (Rxhdr[ZF0] == ZCOMMAND)
+				continue;
+		default:
+			zshhdr(ZNAK, Txhdr);
+			continue;
+		}
+	}
+	return ERROR;
+}
+
+/* Send send-init information */
+sendzsinit()
+{
+	register c;
+	register errors;
+
+	errors = 0;
+	for (;;) {
+		stohdr(0L);
+		zsbhdr(ZSINIT, Txhdr);
+		zsbdata(Myattn, 1+strlen(Myattn), ZCRCW);
+		c = zgethdr(Rxhdr, 1);
+		switch (c) {
+		case ZCAN:
+			return ERROR;
+		case ZACK:
+			return OK;
+		default:
+			if (++errors > 9)
+				return ERROR;
+			continue;
+		}
+	}
+}
+
+/* Send file name and related info */
+zsendfile(buf, blen)
+char *buf;
+{
+	register c;
+
+	for (;;) {
+		Txhdr[ZF0] = Lzconv;	/* file conversion request */
+		Txhdr[ZF1] = Lzmanag;	/* file management request */
+		Txhdr[ZF2] = Lztrans;	/* file transport request */
+		Txhdr[ZF3] = 0;
+		zsbhdr(ZFILE, Txhdr);
+		zsbdata(buf, blen, ZCRCW);
+again:
+		c = zgethdr(Rxhdr, 1);
+		switch (c) {
+		case ZRINIT:
+			goto again;
+		case ZCAN:
+		case TIMEOUT:
+		case ZABORT:
+		case ZFIN:
+			return ERROR;
+		case ZSKIP:
+			close(in); return c;
+		case ZRPOS:
+			lseek(in, Rxpos, 0);
+			Txpos = Rxpos;
+			return zsendfdata();
+		case ERROR:
+		default:
+			continue;
+		}
+	}
+}
+
+/* Send the data in the file */
+zsendfdata()
+{
+	register c, e;
+	register newcnt;
+	register long tcount = 0;
+	static int tleft = 6;	/* Counter for test mode */
+
+	if (Baudrate > 300)
+		blklen = 256;
+	if (Baudrate > 2400)
+		blklen = KSIZE;
+	if (Rxbuflen && blklen>Rxbuflen)
+		blklen = Rxbuflen;
+somemore:
+	//if (setjmp(intrjmp)) {
+waitack:
+	//	switch (c = getinsync()) {
+	//	default:
+	//	case ZCAN:
+	//		close(in);
+		//	return ERROR;
+	//	case ZSKIP:
+	//		close(in);
+		//	return c;
+	//	case ZACK:
+	//	case ZRPOS:
+	//		break;
+	//	}
+//	}
+
+	//signal(SIGINT, onintr);
+	newcnt = Rxbuflen;
+	stohdr(Txpos);
+	zsbhdr(ZDATA, Txhdr);
+
+	/*
+	 * Special testing mode.  This should force receiver to Attn,ZRPOS
+	 *  many times.  Each time the signal should be caught, causing the
+	 *  file to be started over from the beginning.
+	 */
+	if (Testattn) {
+		if ( --tleft)
+			while (tcount < 20000) {
+				//printf(qbf); 
+				//fflush(stdout);
+				tcount += strlen(qbf);
+			}
+		//signal(SIGINT, SIG_IGN); 
+		canit();
+		//sleep(3); 
+		purgeline(); mode(0);
+		//printf("\nsz: Tcount = %ld\n", tcount);
+		if (tleft) {
+			//printf("ERROR: Interrupts Not Caught\n");
+			//exit(1);
+		}
+		//exit(0);
+	}
+
+	do {
+		c = zfilbuf(txbuf, blklen);
+		if (c < blklen)
+			e = ZCRCE;
+		else if (Rxbuflen && (newcnt -= c) <= 0)
+			e = ZCRCW;
+		else
+			e = ZCRCG;
+		zsbdata(txbuf, c, e);
+		Txpos += c;
+		if (e == ZCRCW)
+			goto waitack;
+#ifdef NOTDEF_DOS
+		if ( !carrier()) {
+			return ERROR;
+		}
+		/*
+		 * If the reverse channel can be tested for data,
+		 *  this logic may be used to detect error packets
+		 *  sent by the receiver, in place of setjmp/longjmp
+		 *	miready() returns non 0 if a character is available
+		 */
+		while (miready()) {
+			if (readline(1) == ZPAD) {
+				zsbdata(U.ubuf, 0, ZCRCW);
+				goto somemore;
+			}
+		}
+#endif
+	} while (c == blklen);
+	//signal(SIGINT, SIG_IGN);
+
+	for (;;) {
+		stohdr(Txpos);
+		zsbhdr(ZEOF, Txhdr);
+		switch (getinsync()) {
+		case ZRPOS:
+			goto somemore;
+		case ZRINIT:
+			close(in);
+			return OK;
+		case ZSKIP:
+			close(in);
+			return c;
+		default:
+			close(in);
+			return ERROR;
+		}
+	}
+}
+
+/*
+ * Respond to receiver's complaint, get back in sync with receiver
+ */
+getinsync()
+{
+	register c;
+
+	for (;;) {
+		if (Testattn) {
+			//printf("\r\n\n\n***** Signal Caught *****\r\n");
+			Rxpos = 0; c = ZRPOS;
+		} else
+			c = zgethdr(Rxhdr, 0);
+		switch (c) {
+		case ZCAN:
+		case ZABORT:
+		case ZFIN:
+		case TIMEOUT:
+			return ERROR;
+		case ZRPOS:
+			//clearerr(in);	/* In case file EOF seen */
+			lseek(in, Rxpos, 0);
+			Txpos = Rxpos;
+			return c;
+		case ZACK:
+			return c;
+		case ZRINIT:
+		case ZSKIP:
+			close(in);
+			return c;
+		case ERROR:
+		default:
+			zsbhdr(ZNAK, Txhdr);
+			continue;
+		}
+	}
+}
+/* Say "bibi" to the receiver, try to do it cleanly */
+saybibi()
+{
+	for (;;) {
+		stohdr(0L);
+		zsbhdr(ZFIN, Txhdr);
+		switch (zgethdr(Rxhdr, 0)) {
+		case ZFIN:
+			sendline('O'); sendline('O'); flushmo();
+		case ZCAN:
+		case TIMEOUT:
+			return;
+		}
+	}
+}
+
+/* Local screen character display function */
+bttyout(c)
+{
+	//if (Verbose)
+	//	putc(c, stderr);
+}
+
+/* Send command and related info */
+zsendcmd(buf, blen)
+char *buf;
+{
+	register c, errors;
+	long cmdnum;
+
+//	cmdnum = getpid();
+	errors = 0;
+	for (;;) {
+		stohdr(cmdnum);
+		Txhdr[ZF0] = Cmdack1;
+		zsbhdr(ZCOMMAND, Txhdr);
+		zsbdata(buf, blen, ZCRCW);
+listen:
+		Rxtimeout = 100;		/* Ten second wait for resp. */
+		c = zgethdr(Rxhdr, 1);
+
+		switch (c) {
+		case ZRINIT:
+			continue;
+		case ERROR:
+		case TIMEOUT:
+			if (++errors > Cmdtries)
+				return ERROR;
+			continue;
+		case ZCAN:
+		case ZABORT:
+		case ZFIN:
+		case ZSKIP:
+		case ZRPOS:
+			return ERROR;
+		default:
+			if (++errors > 10)
+				return ERROR;
+			continue;
+		case ZCOMPL:
+			Exitcode = Rxpos;
+			saybibi();
+			return OK;
+		case ZRQINIT:
+			vfile("******** RZ *******");
+			system("rz");
+			vfile("******** SZ *******");
+			goto listen;
+		}
+	}
+}
+

+ 480 - 0
components/utilities/ZMODEM/ZM.C

@@ -0,0 +1,480 @@
+/*
+ *   Z M . C
+ *    ZMODEM protocol primitives
+ *    5-18-86  Chuck Forsberg Omen Technology Inc
+ *
+ * Entry point Functions:
+ *	zsbhdr(type, hdr) send binary header
+ *	zshhdr(type, hdr) send hex header
+ *	zgethdr(hdr, eflag) receive header - binary or hex
+ *	zsbdata(buf, len, frameend) send binary data
+ *	zrbdata(buf, len) receive binary data
+ *	stohdr(pos) store position data in Txhdr
+ *	long rclhdr(hdr) recover position offset from header
+ */
+
+//#ifndef CANFDX
+#include "zmodem.h"
+int Rxtimeout = 100;		/* Tenths of seconds to wait for something */
+//#endif
+#define ERROR (-1)
+static char *frametypes[] = {
+	"TIMEOUT",
+	"ERROR",
+	"ZRQINIT",
+	"ZRINIT",
+	"ZSINIT",
+	"ZACK",
+	"ZFILE",
+	"ZSKIP",
+	"ZNAK",
+	"ZABORT",
+	"ZFIN",
+	"ZRPOS",
+	"ZDATA",
+	"ZEOF",
+	"ZFERR",
+	"ZCRC",
+	"ZCHALLENGE",
+	"ZCOMPL",
+	"ZCAN",
+	"ZFREECNT",
+	"ZCOMMAND",
+	"ZCACK"
+#define FRTYPES 21	/* Total number of frame types in this array */
+};
+
+long int rclhdr(char *hdr);
+int zputhex(int c);
+int zsendline(int c);
+int zgethex(void);
+int zgeth1(void);
+int zrbhdr(char *hdr);
+int zrhhdr(char *hdr);
+int zdlread(void);
+int noxread7(void);
+
+
+/* Send ZMODEM binary header hdr of type type */
+int zsbhdr(int type, char *hdr)
+{
+	int n;
+    unsigned short oldcrc;
+
+	vfile("zsbhdr: %s %lx", frametypes[type+2], rclhdr(hdr));
+	xsendline(ZPAD); xsendline(ZDLE); xsendline(ZBIN);
+
+	zsendline(type); oldcrc = updcrc(type, 0);
+
+	for (n=4; --n >= 0;) {
+		zsendline(*hdr);
+		oldcrc = updcrc(*hdr++, oldcrc);
+	}
+	oldcrc = updcrc(0,updcrc(0,oldcrc));
+	zsendline(oldcrc>>8);
+	zsendline(oldcrc);
+	if (type != ZDATA)
+		flushmo();
+	return 0;
+}
+
+/* Send ZMODEM HEX header hdr of type type */
+int zshhdr(int type, char *hdr)
+{
+	int n;
+    unsigned short oldcrc;
+
+	vfile("zshhdr: %s %lx", frametypes[type+2], rclhdr(hdr));
+	
+	sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
+	zputhex(type);
+
+	oldcrc = updcrc(type, 0);
+	for (n=4; --n >= 0;) {
+		zputhex(*hdr); oldcrc = updcrc(*hdr++, oldcrc);
+	}
+	oldcrc = updcrc(0,updcrc(0,oldcrc));
+	zputhex(oldcrc>>8); zputhex(oldcrc);
+	
+	/* Make it printable on remote machine */
+	sendline(015); sendline(0212);	 /*012*/
+	/*
+	 * Uncork the remote in case a fake XOFF has stopped data flow
+	 */
+	if (type != ZFIN)
+		sendline(021);
+	flushmo();
+	return 0;
+}
+
+/*
+ * Send binary array buf of length length, with ending ZDLE sequence frameend
+ */
+int zsbdata(char *buf, int length, int frameend)
+{
+	register unsigned short oldcrc;
+
+	vfile("zsbdata: length=%d end=%x", length, frameend);
+	oldcrc = 0;
+	for (;--length >= 0;) {
+		zsendline(*buf);
+		oldcrc = updcrc(*buf++, oldcrc);
+	}
+	xsendline(ZDLE); xsendline(frameend);
+	oldcrc = updcrc(frameend, oldcrc);
+
+	oldcrc = updcrc(0,updcrc(0,oldcrc));
+	zsendline(oldcrc>>8);
+	zsendline(oldcrc);
+	if (frameend == ZCRCW)
+		flushmo();
+	return 0;
+}
+
+/*
+ * Receive binary array buf of max length with ending ZDLE sequence
+ *  and CRC.  Returns the ending character or error code.
+ */
+int zrbdata(char *buf, int length)
+{
+	int c;
+    unsigned short oldcrc;
+	int d;
+
+	oldcrc = Rxcount = 0;
+	for (;;) {
+		if ((c = zdlread()) & ~0377) {
+			switch (c) {
+			case GOTCRCE:
+			case GOTCRCG:
+			case GOTCRCQ:
+			case GOTCRCW:
+				oldcrc = updcrc((d=c)&0377, oldcrc);
+				if ((c = zdlread()) & ~0377)
+					goto badcrc;
+				oldcrc = updcrc(c, oldcrc);
+				if ((c = zdlread()) & ~0377)
+					goto badcrc;
+				oldcrc = updcrc(c, oldcrc);
+				if (oldcrc & 0xFFFF) {
+badcrc:
+					zperr("Bad data packet CRC");
+					return ERROR;
+				}
+				vfile("zrbdata: Rxcount = %d ret = %x",
+				  Rxcount, d);
+				return d;
+			case GOTCAN:
+				zperr("ZMODEM: Sender Canceled");
+				return ZCAN;
+			case TIMEOUT:
+				zperr("ZMODEM data packet TIMEOUT");
+				return c;
+			default:
+				zperr("ZMODEM bad data packet ret=%x", c);
+				return c;
+			}
+		}
+		if (--length < 0) {
+			zperr("ZMODEM binary data packet too long");
+			return ERROR;
+		}
+		++Rxcount;
+		*buf++ = c;
+		oldcrc = updcrc(c, oldcrc);
+		continue;
+	}
+}
+
+/*
+ * Read a ZMODEM header to hdr, either binary or hex.
+ *  eflag controls local display of non zmodem characters:
+ *	0:  no display
+ *	1:  display printing characters only
+ *	2:  display all non ZMODEM characters
+ *  On success, set Zmodem to 1 and return type of header.
+ *   Otherwise return negative on error
+ */
+int zgethdr(char *hdr, int eflag)
+{
+	int c, n;
+
+	n = Baudrate;	/* Max characters before start of frame */
+again:
+	Rxframeind = Rxtype = 0;
+	switch (c = noxread7()) {
+	case TIMEOUT:
+		goto fifi;
+	case ZDLE:
+		if (noxread7() == ZDLE) {
+			c = ZCAN; goto fifi;
+		}
+	/* **** FALL THRU TO **** */
+	default:
+		if ( --n == 0) {
+			zperr("ZMODEM Garbage count exceeded");
+			return(ERROR);
+		}
+		if (eflag && ((c &= 0177) & 0140))
+			bttyout(c);
+		else if (eflag > 1)
+			bttyout(c);
+		goto again;
+	case ZPAD:
+		break;
+	}
+splat:
+	switch (c = noxread7()) {
+	case ZPAD:
+		goto splat;
+	case TIMEOUT:
+		goto fifi;
+	default:
+		goto again;
+	case ZDLE:
+		break;
+	}
+
+	switch (c = noxread7()) {
+	case TIMEOUT:
+		goto fifi;
+	case ZBIN:
+		Rxframeind = ZBIN;
+		c =  zrbhdr(hdr);
+		break;
+	case ZHEX:
+		Rxframeind = ZHEX;
+		c =  zrhhdr(hdr);
+		break;
+	case ZDLE:
+		if (noxread7() == ZDLE) {
+			c = ZCAN; goto fifi;
+		}
+	/* **** FALL THRU TO **** */
+	default:
+		goto again;
+	}
+	Rxpos = hdr[ZP3] & 0377;
+	Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
+	Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
+	Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
+fifi:
+	switch (c) {
+	case GOTCAN:
+		c = ZCAN;
+	/* **** FALL THRU TO **** */
+	case ZNAK:
+	case ZCAN:
+	case ERROR:
+	case TIMEOUT:
+		zperr("ZMODEM: Got %s header", frametypes[c+2]);
+	default:
+		if (c >= -2 && c <= FRTYPES)
+			vfile("zgethdr: %s %lx", frametypes[c+2], Rxpos);
+		else
+			vfile("zgethdr: %d %lx", c, Rxpos);
+	}
+	return c;
+}
+
+/* Receive a binary style header (type and position) */
+int zrbhdr(char *hdr)
+{
+	int c, n;
+    unsigned short oldcrc;
+
+	if ((c = zdlread()) & ~0377)
+		return c;
+	Rxtype = c;
+	oldcrc = updcrc(c, 0);
+
+	for (n=4; --n >= 0;) {
+		if ((c = zdlread()) & ~0377)
+			return c;
+		oldcrc = updcrc(c, oldcrc);
+		*hdr++ = c;
+	}
+	if ((c = zdlread()) & ~0377)
+		return c;
+	oldcrc = updcrc(c, oldcrc);
+	if ((c = zdlread()) & ~0377)
+		return c;
+	oldcrc = updcrc(c, oldcrc);
+	if (oldcrc & 0xFFFF) {
+		zperr("Bad Header CRC"); return ERROR;
+	}
+	Zmodem = 1;
+	return Rxtype;
+}
+
+/* Receive a hex style header (type and position) */
+int zrhhdr(char *hdr)
+{
+	int c;
+	unsigned short oldcrc;
+	int n;
+
+	if ((c = zgethex()) < 0)
+		return c;
+	Rxtype = c;
+	oldcrc = updcrc(c, 0);
+
+	for (n=4; --n >= 0;) {
+		if ((c = zgethex()) < 0)
+			return c;
+		oldcrc = updcrc(c, oldcrc);
+		*hdr++ = c;
+	}
+	if ((c = zgethex()) < 0)
+		return c;
+	oldcrc = updcrc(c, oldcrc);
+	if ((c = zgethex()) < 0)
+		return c;
+	oldcrc = updcrc(c, oldcrc);
+	if (oldcrc & 0xFFFF) {
+		zperr("Bad Header CRC"); return ERROR;
+	}
+	if (readline(1) == '\r')	/* Throw away possible cr/lf */
+		readline(1);
+	Zmodem = 1; return Rxtype;
+}
+
+/* Send a byte as two hex digits */
+int zputhex(int c)
+{
+	static char	digits[]	= "0123456789abcdef";
+
+	if (Verbose>4)
+		vfile("zputhex: %x", c);
+	sendline(digits[(c&0xF0)>>4]);
+	sendline(digits[(c)&0xF]);
+	return 0;
+}
+
+/* Send character c with ZMODEM escape sequence encoding */
+int zsendline(int c)
+{
+	switch (c & 0377) {
+	case ZDLE:
+	case 021:
+	case 023:
+	case 0221:
+	case 0223:
+		xsendline(ZDLE);
+		c ^= 0100;
+	/* **** FALL THRU TO **** */
+	default:
+		xsendline(c);
+	}
+	return 0;
+}
+
+/* Decode two lower case hex digits into an 8 bit byte value */
+int zgethex(void)
+{
+	int c;
+
+	c = zgeth1();
+	if (Verbose>4)
+		vfile("zgethex: %x", c);
+	return c;
+}
+int zgeth1(void)
+{
+	int c, n;
+
+	if ((c = noxread7()) < 0)
+		return c;
+	n = c - '0';
+	if (n > 9)
+		n -= ('a' - ':');
+	if (n & ~0xF)
+		return ERROR;
+	if ((c = noxread7()) < 0)
+		return c;
+	c -= '0';
+	if (c > 9)
+		c -= ('a' - ':');
+	if (c & ~0xF)
+		return ERROR;
+	c += (n<<4);
+	return c;
+}
+
+/*
+ * Read a byte, checking for ZMODEM escape encoding
+ *  including CAN-CAN which represents a quick abort
+ */
+int zdlread(void)
+{
+	int c;
+
+	if ((c = readline(Rxtimeout)) != ZDLE)
+		return c;
+	if ((c = readline(Rxtimeout)) < 0)
+		return c;
+	switch (c) {
+	case ZDLE:
+		return GOTCAN;
+	case ZCRCE:
+	case ZCRCG:
+	case ZCRCQ:
+	case ZCRCW:
+		return (c | GOTOR);
+	case ZRUB0:
+		return 0177;
+	case ZRUB1:
+		return 0377;
+	default:
+		if ((c & 0140) ==  0100)
+			return (c ^ 0100);
+		break;
+	}
+	zperr("Got bad ZMODEM escape sequence %x", c);
+	return ERROR;
+}
+
+/*
+ * Read a character from the modem line with timeout.
+ *  Eat parity, XON and XOFF characters.
+ */
+int noxread7(void)
+{
+	int c;
+
+	for (;;) {
+		if ((c = readline(Rxtimeout)) < 0)
+			return c;
+		switch (c &= 0177) {
+		case XON:
+		case XOFF:
+			continue;
+		default:
+			return c;
+		}
+	}
+}
+
+/* Store long integer pos in Txhdr */
+int stohdr(long int pos)
+{
+	Txhdr[ZP0] = pos;
+	Txhdr[ZP1] = pos>>8;
+	Txhdr[ZP2] = pos>>16;
+	Txhdr[ZP3] = pos>>24;
+	return 0;
+}
+
+/* Recover a long integer from a header */
+long
+int rclhdr(char *hdr)
+{
+    long int l;
+
+	l = (hdr[ZP3] & 0377);
+	l = (l << 8) | (hdr[ZP2] & 0377);
+	l = (l << 8) | (hdr[ZP1] & 0377);
+	l = (l << 8) | (hdr[ZP0] & 0377);
+	return l;
+}
+

+ 2056 - 0
components/utilities/ZMODEM/ZMODEM.DOC

@@ -0,0 +1,2056 @@
+
+
+
+     The ZMODEM Asynchronous Inter Application File Transfer Protocol
+
+                              Chuck Forsberg
+
+                           Omen Technology Inc
+
+
+                              Chuck Forsberg
+                           Omen Technology Inc
+                   17505-V Northwest Sauvie Island Road
+                          Portland Oregon 97231
+                           Voice: 503-621-3406
+            Modem (Telegodzilla): 503-621-3746 Speed 1200,300
+                          Compuserve: 70715,131
+                    UUCP: ...!tektronix!reed!omen!caf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Chapter 0               rev051486 Printed 5-16-86                        1
+
+
+
+
+
+
+
+Chapter 0               rev051486 Printed 5-16-86                        2
+
+
+
+1.  INTENDED AUDIENCE
+
+This document is intended for systems programmers and other technically
+qualified people who choose and implement asynchronous file transfer
+protocols over dial-up networks and related environments.
+
+
+2.  ACKNOWLEDGMENTS
+
+Encouragement and suggestions by Stuart Mathison, Thomas Buck, John Wales,
+Ward Christensen, and Irv Hoff are gratefully acknowledged.
+
+
+3.  RELATED DOCUMENTS
+
+The following files should be available for reference while studying this
+document:
+
+YMODEM.DOC Describes the XMODEM and YMODEM file transfer protocols
+
+ZMODEM.H Provides definitions for the manifest constants referenced
+        herein.
+
+rz.c, sz.c, rbsb.c Unix source code for operating ZMODEM programs.
+
+rz.1, sz.1 Manual pages for rz and sz.
+
+zm.c, zmodem.h Operating system independent ZMODEM subroutines, header
+        file.
+
+
+4.  ROSETTA STONE
+
+Here are some definitions which reflect the current vernacular in the
+computer media.  The attempt here is identify the file transfer protocol
+rather than specific programs.
+
+Frame   A ZMODEM frame consists of a header packet and 0 or more data
+        packets.
+
+XMODEM  refers to the original 1979 file transfer etiquette introduced by
+        Ward Christensen's 1979 MODEM2 program.  It's also called the
+        MODEM or MODEM2 protocol.  Some who are unaware of MODEM7's
+        unusual batch file mode call it MODEM7.  Other aliases include
+        "CP/M Users's Group" and "TERM II FTP 3".  This protocol is
+        supported by every serious communications program because of its
+        universality, simplicity, and reasonable performance.
+
+XMODEM/CRC replaces XMODEM's 1 byte checksum with a two byte Cyclical
+        Redundancy Check (CRC-16), giving modern error detection
+        protection.
+
+
+
+Chapter 4               rev051486 Printed 5-16-86                        2
+
+
+
+
+
+
+
+Chapter 4               rev051486 Printed 5-16-86                        3
+
+
+
+YMODEM  refers to the XMODEM/CRC protocol with the throughput and/or batch
+        transmission enhancements described in YMODEM.DOC.
+
+ZMODEM  Zmodem is a second generation streaming protocol for text and
+        binary file transmission between applications running on
+        microcomputers and mainframes.
+
+
+5.  WHY DEVELOP ZMODEM?
+
+Since its development half a decade ago, the Ward Christensen MODEM
+protocol has enabled a wide variety of computer systems to interchange
+data.  There is hardly a communications program that doesn't at least
+claim to support this protocol, now called XMODEM.
+
+Advances in computing, modems and networking have spread the XMODEM
+protocol far beyond the micro to micro environment for which it was
+designed.  These application have exposed some weaknesses:
+
+   + The user interface is suitable for computer hobbyists.  Three or four
+     commands must be keyboarded to transfer each file.
+
+   + The short block length causes throughput to suffer when used with
+     timesharing systems, packet switched networks, satellite circuits,
+     and buffered (error correcting) modems.
+
+   + The 8 bit checksum and unprotected transactions allow undetected
+     errors and disrupted file transfers.
+
+   + Only one file can be sent per command.  The file name has to be given
+     twice, first to the sending program and then again to the receiving
+     program.
+
+   + The transmitted file accumulates as many as 127 extraneous bytes.
+
+   + The modification date and other file attributes are lost.
+
+   + XMODEM requires complete 8 bit transparency, all 256 codes.  XMODEM
+     will not operate over some networks that need flow control.
+
+A number of other protocols have been developed over the years, but none
+have displaced XMODEM to date.
+
+   + Lack of public domain documentation and example programs have kept
+     proprietary protocols such as MNP, Blast, and others tightly bound to
+     the fortunes of their suppliers.
+
+   + Hardware and/or software complexity discourages the widespread
+     application of BISYNC, SDLC, HDLC, X.25, and X.PC protocols.
+
+
+
+
+
+Chapter 5               rev051486 Printed 5-16-86                        3
+
+
+
+
+
+
+
+Chapter 5               rev051486 Printed 5-16-86                        4
+
+
+
+   + Link level protocols such as X.25, X.PC, and MNP do not manage
+     application to application file transfers.
+
+   + The Kermit protocol was developed to allow file transfers in
+     environments hostile to XMODEM.  The performance compromises
+     necessary to accomodate non transparent environments limit Kermit's
+     efficiency.  Even with completely transparent channels, Kermit
+     control character quoting limits the efficiency of binary file
+     transfers to about 75 per cent.[1]
+
+     Kermit Sliding Windows ("SuperKermit") improves throughput over
+     networks at the cost of increased complexity.  SuperKermit state
+     transitions are encoded in a special language "wart" which requires a
+     C compiler.  The SuperKermit C code requires full duplex
+     communications and the ability to check for the presence of
+     characters in the input queue, precluding its implementation on some
+     operating systems.
+
+     A number of submodes are used in various Kermit programs, including
+     different methods of transferring binary files.  Two Kermit programs
+     will mysteriously fail to operate with each other if these submodes
+     are not matched.
+
+A number of extensions to the XMODEM protocol have been made under the
+collective name YMODEM.
+
+ + YMODEM-k uses 1024 byte blocks to reduce the overhead from transmission
+   delays by 87 per cent compared to XMODEM, but network delays can still
+   degrade performance.  Some networks may not be transmit the 1024 byte
+   packets unmodified.
+
+ + The handling of files that are not a multiple of 1024 or 128 bytes is
+   awkward, especially if the file length is not known, or changes during
+   transmission.
+
+ + YMODEM-g provides efficient batch file transfers, preserving the exact
+   file length and file modification date.  YMODEM-g is essentially
+   insensitive to network delays.  Because it does not support error
+   recovery, YMODEM-g is usually used hardwired or with a reliable link
+   level protocol.  IF YMODEM-g detects a CRC error, data transfers are
+   aborted.  YMODEM-g is easy to implement because it closely resembles
+   XMODEM-CRC.
+
+Another XMODEM "extension" is protocol cheating, referred to as "Turbo
+Download" and OverThruster.  [2] These sometimes improve XMODEM throughput
+
+
+__________
+
+ 1. Some Kermit programs support run length encoding.
+
+
+
+
+Chapter 5               rev051486 Printed 5-16-86                        4
+
+
+
+
+
+
+
+Chapter 5               rev051486 Printed 5-16-86                        5
+
+
+
+at the expense of error recovery.
+
+The ZMODEM Protocol is proposed as a means of addressing the weaknesses
+described above while maintaining as much of XMODEM's simplicity and prior
+art as possible.
+
+
+
+6.  ZMODEM Protocol Design Criteria
+
+The design of a file transfer protocol is an engineering compromise
+between conflicting requirements:
+
+6.1  Ease of Use
+
+ + ZMODEM allows either program to initiate file transfers, passing
+   commands and/or modifiers to the other program.
+
+ + File names need be entered only once, menu selections are possible.
+
+ + Wild Card names may be used with batch transfers.
+
+ + Minimum keystrokes required to initiate transfers.
+
+ + ZRQINIT packet sent by sending program can trigger automatic downloads.
+
+ + ZMODEM can step down to YMODEM if the other end does not support
+   ZMODEM.[1]
+
+6.2  Throughput
+
+ZMODEM is designed for optimum performance with minimum degradation caused
+by delays introduced by packet switched networks and timesharing systems.
+
+ZMODEM is optimized for best throughput when line hits occur infrequently.
+This assumption markedly reduces code complexity and memory requirements.
+ZMODEM protocol features enhance rapid error recovery compared to network
+compatible XMODEM implementations.
+
+It is assumed that many transfers will originate from a timesharing system
+connected to a packet switched network.  ZMODEM provides features to allow
+for simple, efficient implementation on timesharing hosts.
+
+
+
+__________________________________________________________________________
+
+ 2. Omen Technology Trademark
+
+ 1. Provided the transmission medium accomodates YMODEM.
+
+
+
+
+Chapter 6               rev051486 Printed 5-16-86                        5
+
+
+
+
+
+
+
+Chapter 6               rev051486 Printed 5-16-86                        6
+
+
+
+File transfers begin immediately regardless of which program is started
+first, without the 10 second delay associated with XMODEM.
+
+
+6.3  Integrity and Robustness
+
+All packets are protected with 16 bit CRC.  Proprietary alogrithyms[2] are
+not needed for reliable transfers.
+
+A security challenge guards againgst Trojan Horse messages.
+
+6.4  Ease of Implementation
+
+ZMODEM accomodates a wide variety of systems:
+
+ + Microcomputers that cannot overlap disk and serial i/o
+
+ + Microcomputers that cannot overlap serial send and receive
+
+ + Computers and/or networks requiring XON/XOFF flow control
+
+ + Computers that cannot check the serial input queue for the presence of
+   data without having to wait for the data to arrive.
+
+Although ZMODEM provides "hooks" for multiple "threads", ZMODEM is not
+intended to replace link level protocols such as X.25.
+
+ZMODEM accomodates network and timesharing system delays by continuously
+transmitting data unless the receiver interrupts the sender to request
+retransmission of garbled data.  ZMODEM in effect uses the entire file as
+a window.[3]
+
+ZMODEM provides a general purpose application to application file transfer
+protocol which may be used directly or with with reliable link level
+protocols such as X.25, MNP, Fastlink, etc.
+
+
+7.  ZMODEM BASICS
+
+
+
+
+
+
+
+__________
+
+ 2. Unique to Professional-YAM, PowerCom, etc.
+
+ 3. Streaming strategey is discussed in a coming chapter.
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        6
+
+
+
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        7
+
+
+
+7.1  Packetization
+
+ZMODEM frames somewhat different from X/YMODEM blocks.  X/YMODEM blocks
+are not used for the following reasons:
+
+ + Block numbers are limited to 256
+
+ + No provision for variable length blocks
+
+ + Line hits corrupt protocol signals, causing failed file transfers.  In
+   particular, modem errors sometimes generate false block numbers, false
+   EOTs and false ACKs.  False ACKs are the most troublesome as they cause
+   the sender to lose synchronization with the receiver.
+
+   State of the art X/YMODEM programs such as Professional-YAM and
+   PowerCom overcome some of these weaknesses with clever proprietary
+   code, but a stronger protocol is desired.
+
+ + It is difficult to determine the beginning and ends of X/YMODEM blocks
+   when line hits cause a loss of synchronization.  This precludes rapid
+   error recovery.
+
+7.2  Link Escape Encoding
+
+ZMODEM acheives data transparency by extending the 8 bit character set
+(256 codes) with escape sequences based on the ZMODEM data link escape
+character ZDLE.[1]
+
+Link Escape coding permits variable length data packets without the
+overhead of a separate byte count.  It allows the beginning of frames to
+be detected without special timing techniques, facilitating rapid error
+recovery.
+
+Link Escape coding does add some overhead.  The worst case, a file
+consisting entirely of ZDLE characters, would incur a 50% overhead.
+
+The ZDLE character is special.  ZDLE represents a control sequence of some
+sort.  If a ZDLE character appears in the data sent within a binary
+packet, it is prefixed with ZDLE, then sent as ZDLEE.
+
+The value for ZDLE is octal 030 (ASCII CAN).  This particular value was
+chosen to allow a string of CAN characters to abort a ZMODEM session,
+compatible with X/YMODEM session abort.
+
+
+
+__________
+
+ 1. This and other constants are defined in the zmodem.h include file.
+    Please note that constants with a leading 0 are octal constants in C.
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        7
+
+
+
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        8
+
+
+
+Since CAN is not used for normal terminal operations, communications
+programs can monitor the data flow for ZDLE.  The following characters can
+be scanned to detect the ZRQINIT packet, the invitation to automatically
+download commands or files.
+
+Two successive CAN characters will abort a ZMODEM session.  Experience
+with YMODEM file transfers suggests that this does not impair the
+robustness of the protocol.  A minimum of 8 CAN are sent, so the ZMODEM
+subroutines can be modified to require more successive CAN characters to
+signal an abort.
+
+The receiving program will decode any sequence of ZDLE followed by a byte
+with bit 6 set and bit 5 reset (upper case letter, either parity) to the
+equivalent control character by inverting bit 6.  This allows the
+transmitter to escape any control character that cannot be sent by the
+communications medium.  The ZMODEM software currently escapes ZDLE, 021,
+0221, 023, and 0223.  In addition, the receiver recognizes escapes for
+0177 and 0377 should these characters need to be escaped.
+
+7.3  Header Packet Information
+
+All ZMODEM frames begin with a header packet which may be sent in binary
+or HEX form.  ZMODEM uses a single routine to recognize binary and hex
+header packets.  Either form of the header packet contains the same raw
+information:
+
+ + A type byte[2] Future extensions to ZMODEM may use the high order bits
+   of the type byte to indicate thread selection.
+
+ + Four bytes of data indicating flags and/or numeric quantities depending
+   on the packet type
+
+                Figure 1.  Order of Bytes in Header Packet
+
+
+                   TYPE:  packet Type
+                   F0: Flags least significant byte
+                   P0: file Position least significant
+                   P3: file Position most significant
+
+                           TYPE  F3 F2 F1 F0
+                           --------------
+                           TYPE  P0 P1 P2 P3
+
+
+
+__________
+
+ 2. The packet types are cardinal numbers beginning with 0 to minimize
+    state transition table memory requirements.
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        8
+
+
+
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        9
+
+
+
+7.4  Binary Header Packet
+
+A binary header packet is only sent by the sending program to the
+receiving program.
+
+A binary header packet begins with the sequence ZPAD, ZDLE, ZBIN.
+
+The frame type byte is ZDLE encoded.
+
+The four position/flags bytes are ZDLE encoded.
+
+A two byte CRC of the frame type and position/flag bytes is ZDLE encoded.
+
+0 or more binary data packets will follow depending on the frame type.
+
+The function zsbhdr transmits a binary header packet.  The function
+zgethdr receives a binary or hex header packet.
+
+                     Figure 2.  Binary Header Packet
+            * * ZDLE TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2
+
+
+7.5  HEX Header Packet
+
+The receiver sends responses in hex header packets.  The sender also uses
+hex header packets when they are not followed by binary data packets.
+
+Hex encoding is required to support XON/XOFF flow control.  The hex header
+receiving routine ignores flow control characters.
+
+Use of Kermit style encoding for control and paritied characters was
+considered and rejected because of increased possibility of interacting
+with some timesharing systems's line edit functions.  Use of HEX packets
+from the receiving program allows control characters to be used to
+interrupt the sender when errors are detected.  Except for header packet
+types that imply data packets to follow, a HEX header packet may be used
+in place of a binary header packet.
+
+A hex header packet begins with the sequence ZPAD, ZPAD, ZDLE, ZHEX.  The
+zgethdr routine synchronizes in the ZPAD-ZDELE sequence.  The extra ZPAD
+allows other parts of the program to detect a ZMODEM packet and then call
+zgethdr to receive the packet.
+
+The type byte, the four position/flag bytes, and the CRC thereof are sent
+in hex using the character set 01234567890abcdef.  Upper case hex digits
+are not allowed; they false trigger X/YMODEM programs.
+
+A carriage return, line feed, and XON are appended to the HEX header
+packet but are not considered to be part of it.  The CR/LF aids debugging
+from printouts.  The XON releases the sender from spurious XOFF flow
+control characters generated by line noise, a common occurrence.
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                        9
+
+
+
+
+
+
+
+Chapter 7               rev051486 Printed 5-16-86                       10
+
+
+
+0 or more ASCII Encoded data packets will follow depending on the frame
+type.
+
+The function zshhdr sends a hex header packet.
+
+                       Figure 3.  HEX Header Packet
+       * * ZDLE TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CR LF XON
+
+(TYPE, F3...F0, CRC-1, and CRC-2 are each sent as two hex digits.)
+
+
+7.6  Binary Data Packets
+
+Binary data packets immediately follow the associated binary header
+packet.  A binary data packet contains 0 to 1024 bytes of data.
+Recommended length values are 256 bytes below 4800 bps, 1024 above 4800
+bps or when the data link is known to be relatively error free.
+
+No padding is used with binary data packets.  The data bytes are ZDLE
+encoded and transmitted.  A ZDLE and frameend are then sent, followed by
+two ZDLE encoded CRC bytes.  The CRC accumulates the data bytes and
+frameend.
+
+The function zsbdata sends a binary data packet.  The function zrbdata
+receives a binary data packet.
+
+7.7  ASCII Encoded Data Packet
+
+The format of ASCII Encoded data packets is not currently specified.
+These would be used for server commands, etc.
+
+
+8.  PROTOCOL TRANSACTION OVERVIEW
+
+As with the XMODEM recommendation, ZMODEM timing is receiver driven.  The
+transmitter should not time out at all, except to abort the program if no
+packets are received for an extended period of time, say one minute.[1]
+
+To start a ZMODEM file transfer session, the sending program is called
+with the names of the desired file(s) and option(s).
+
+The sending program sends the string "rz\r" to invoke the receiving
+program from a possible command mode.  The "rz" followed by carriage
+return activates a ZMODEM receive program or command if it were not
+already active.
+
+
+__________
+
+ 1. Special considerations apply when sending commands.
+
+
+
+
+Chapter 8               rev051486 Printed 5-16-86                       10
+
+
+
+
+
+
+
+Chapter 8               rev051486 Printed 5-16-86                       11
+
+
+
+The sender may then display a message intended for human consumption, such
+as a list of the files requested, etc.
+
+Then the sender sends a ZRQINIT packet.  The ZRQINIT packet causes a
+previously started receive program to send its ZRINIT packet without
+delay.
+
+In an interactive or conversational mode, the receiving application may
+monitor the data stream for ZDLE.  The following characters may be scanned
+for B000000 indicating a ZRQINIT packet, a command to download a command
+or data.
+
+The sending program awaits a command from the receiving program to start
+file transfers.  If a "C", "G", or NAK is received, an XMODEM or YMODEM
+file transfer is indicated, and file transfer(s) use the X/YMODEM
+protocol.  Note: With ZMODEM and YMODEM Batch, the sending program
+provides the file name, but not with XMODEM.
+
+When the ZMODEM receive program starts, it immediately sends a ZRINIT
+packet to initiate ZMODEM file transfers, or a ZCHALLENGE packet to verify
+the sending program.  The receive program resends its packet at repsonse
+time intervals for a suitable period of time (40 seconds typical) before
+falling back to X/YMODEM protocol.  If the receiving program receives a
+ZRQINIT packet, it resends the ZRINIT packet.  If the sending program
+receives the ZCHALLENGE packet, it places the data in ZP0...ZP3 in an
+answering ZACK packet.
+
+If the receiving program receives a ZRINIT packet, it is an echo
+indicating that the sending program is not operational.
+
+Eventually the sending program correctly receives the ZRINIT packet.
+
+The sender may then respond with an optional ZSINIT frame to set the
+receiving program's Attention string.  The receiver sends a ZACK packet in
+response, containing the serial number of the receiving program, or 0.
+
+The sender then sends a ZFILE header with ZMODEM Conversion, Management,
+and Transport options[2] followed by a ZCRCW data packet containing the
+file name, file length, modification date, and other information identical
+to that used by YMODEM Batch.
+
+The receiving program should insure the pathname and options are
+compatible with its operating environment and local security requirements.
+
+
+
+
+__________
+
+ 2. See below, under ZFILE packet type.
+
+
+
+
+Chapter 8               rev051486 Printed 5-16-86                       11
+
+
+
+
+
+
+
+Chapter 8               rev051486 Printed 5-16-86                       12
+
+
+
+       If the receiver has a file with the same name and length,
+       it may respond with a ZCRC packet, which requires the
+       sender to permorm a 16 bit CRC on the file and transmit the
+       CRC in ZP0...ZP1 of a ZCRC packet.  The receiver uses this
+       information to determine whether to accept the file or skip
+       it.  This sequence is triggered by the ZMCRC Management
+       Option.
+
+The receiver may then respond with a ZSKIP packet, which causes the
+sender to process the next file (if any) in the batch.
+
+A ZRPOS packet from the receiver initiates transmission of the file data
+starting at the offset in the file specified in the ZRPOS packet.
+Normally the receiver specifies the data transfer begin begin at offset 0
+in the file.
+       The receiver may start the transfer further down in the
+       file.  This allows a file transfer interrupted by a loss
+       or carrier or system crash to be completed on the next
+       connection without requiring the entire file to be
+       retransmitted.[3] If downloading a file from a timesharing
+       system that becomes sluggish, the transfer can be
+       interrupted and resumed later with no loss of data.
+
+The sender sends a ZDATA binary header packet (with file position)
+followed by one or more data packets.
+
+The receiver compares the file position in the ZDATA header with the
+number of characters successfully received to the file.  If they do not
+agree, a ZRPOS error response is generated to force the sender to the
+right position within the file.[4]
+
+A data packet terminated by ZCRCGO and CRC does not elicit a response
+unless an error is detected; more data packet(s) follow immediately.
+
+       ZCRCQ data packets expect a ZACK response (with the file
+       offset) if no error, otherwise a ZRPOS response (with the
+       last good file offset).  Another data packet continues
+       immediately.  ZCRCQ packets are not used if the receiver
+       does not indicate FDX ability with the CANFDX bit.
+
+ZCRCW data packets expect a response before the next frame is sent.  If
+the receiver does not indicate overlapped I/O capability with the
+
+
+__________
+
+ 3. This does not apply to files that have been translated.
+
+ 4. If the ZMSPARS option is used, the receiver instead seeks to position
+    in the ZDATA packet.
+
+
+
+
+Chapter 8               rev051486 Printed 5-16-86                       12
+
+
+
+
+
+
+
+Chapter 8               rev051486 Printed 5-16-86                       13
+
+
+
+CANOVIO bit, or by setting a buffer size, the sender uses the ZCRCW to
+allow the receiver to write its buffer before sending more data.
+
+       A zero length data frame may be used as a sending idle
+       packet to prevent the receiver from timing out in case
+       data is not immediately available to the sender.
+
+In the absence of fatal error, the sender eventually encounters end of
+file.  If the end of file is encountered within a frame, the frame is
+closed with a ZCRCE data packet which does not elicit a response
+except in case of error.
+
+The sender sends a ZEOF packet with the file ending offset equal to
+the number of characters in the file.  The receiver compares this
+number with the number of characters received.  If the receiver has
+received all of the file, it closes the file.  If the file close was
+satisfactory, the receiver responds with ZRINIT.  If the receiver has
+not received all the bytes of the file, the receiver sends ZRPOS with
+the current file offset, forcing the sender to resend the missing
+data.  (If the receiver cannot properly close the file, a ZFERR packet
+is sent.)
+
+       After all files are processed, any further protocol
+       errors should not prevent the sending program from
+       returning with a success status.
+
+The sender closes the session with a ZEXIT header packet.  The
+receiver acknowledges this with its own ZEXIT packet.
+
+When the sender receives the acknowledging packet, it sends two
+characters, "OO" (Over and Out) and exits to the operating system or
+application that invoked it.  The receiver waits briefly for the "O"
+characters, then exits whether they were received or not.
+
+8.1  Session Cancel Packet
+
+The Cancel packet consists of two ZPAD characters, eight CAN
+characters, and an optional ten backspace characters.  First, the
+Attn sequence is executed if the receiving program has been receiving
+data in streaming mode.  The ZPAD characters allow sending programs
+that sample the reverse data stream to check for a single character
+code indicating a packet from the receiver.  The trailing backspace
+characters attempt to erase the effects of the other characters if
+they are received by a command interpreter.
+
+        static char canistr[] = {
+ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0         };
+
+
+
+
+
+
+
+Chapter 9               rev051486 Printed 5-16-86                       13
+
+
+
+
+
+
+
+Chapter 9               rev051486 Printed 5-16-86                       14
+
+
+
+9.  ZMODEM STREAMING TECHNIQUES
+
+ZMODEM allows choices of several data streaming methods selected
+according to the limitations of the sending environment, receiving
+environment, and transmission channel(s).
+
+
+9.1  Full Streaming with Sampling
+
+If the computers can overlap serial I/O with disk I/O, and if the
+sender can sample the reverse channel for the presence of data
+without having to wait, full streaming can be used with no Attn
+sequence required.  The sender begins data transmission with a ZDATA
+header and continuous ZCRCG data packets.  When the receiver detects
+an error, it executes the Attn sequence and then sends a ZRPOS packet
+to force the sender back to the correct position within the file.  At
+the end of each transmitted packet, the sender checks for the
+presence of an error packet from the receiver.  To do this, the
+sender may sample the reverse data stream for the presence of a ZPAD
+character.
+
+Such a program would sample the reverse channel for ZPAD.  If seen,
+an empty ZCRCW data packet is sent (in case the receiver was still
+reading packets) and then the receiver's response packet is read and
+acted upon.  The code fragment in sz.c beginning at NOTDEF_DOS would
+perform this function.
+
+
+9.2  Full Streaming with Interrupt
+
+The method above cannot be used if if the reverse data stream cannot
+be sampled without entering an I/O wait.  An alternate method is to
+instruct the receiver to interrupt the sending program when an error
+is detected.
+
+The receiver can interrupt the sender with a control character, break
+signal, or combination thereof, as specified in the ZSINIT frame sent
+by the sending program.
+
+When the sending program "catches" this interrupt, it reads a HEX
+packet (normally ZRPOS) from the receiver and takes appropriate
+action.  The Unix sb.c program uses a setjmp/longjmp call and the
+getinsync() function to read the receiver's error packet and take
+appropriate action.
+
+
+
+
+
+
+
+
+
+
+Chapter 9               rev051486 Printed 5-16-86                       14
+
+
+
+
+
+
+
+Chapter 9               rev051486 Printed 5-16-86                       15
+
+
+
+9.3  Full Streaming with a Sliding Window
+
+If none of the above methods is applicable, hope is not yet lost.  If
+the sender can buffer responses from the receiver, the sender can use
+ZCRCQ packets to get ACKs from the receiver without interrupting the
+transmission of data.  After a sufficient number of ZCRCQ packets
+have been sent, the sender can read one of the one or more packets
+that should have arrived in it's receive interrupt buffer.
+
+A problem with this method is the probability of wasting an excessive
+amount of time responding to the receiver's error packet.
+
+9.4  No Streaming
+
+If the receiver cannot overlap serial and disk I/O, it uses the
+ZRINIT frame to specify a buffer length which the sender will not
+overflow.  The sending program sends a ZCRCW packet and waits for an
+ZACK packet before sending the next segment of the file.
+
+If the sending program supports reverse data stream sampling or
+interrupt, error recovery will be faster (on average) than a protocol
+(such as YMODEM) that sends "monolithic" blocks.
+
+
+10.  ATTENTION SEQUENCE
+
+The receiving program sends the Attn sequence whenever it detects an
+error and needs to interrupt the sending program.
+
+The default Attn string value is empty (no Attn sequence).  The
+receiving program resets Attn to the empty default before each
+transfer session.
+
+The sender speficies the Attn sequence in its optional ZSINIT frame.
+The Attn string is terminated with a null.
+
+Two meta-characters perform special functions:
+
+   + \335 (octal) Sends a break signal
+
+   + \336 (octal) Pauses one second
+
+
+11.  PACKET/FRAME TYPES
+
+The numeric values for the values shown in boldface are given in
+zmodem.h.
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       15
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       16
+
+
+
+11.1  ZRQINIT
+
+Sent once by the sending program, to trigger the receiving program to
+send its ZRINIT packet.  This aviods the aggravatimg startup delay
+associated with XMODEM and Kermit transfers.
+
+ZF0 contains ZCOMMAND if the program is attempting to send a command,
+0 otherwise.
+
+11.2  ZRINIT
+
+Sent by the receiving program.  ZF0 and ZF1 contain the  bitwise or
+of the receiver capability flags:
+#define CANFDX  1 /* Rx can send and receive FDX */
+#define CANOVIO 2 /* Rx can receive during disk I/O */
+#define CANBRK  4 /* Rx can send a break signal */
+#define CANCRY  8 /* Receiver can decrypt */
+
+ZP0 and ZP1 contain the size of the receiver's buffer in bytes, or 0
+if nonstop I/O is allowed.
+
+11.3  ZSINIT
+
+Sender sends capability flags (currently all 0) (none currently
+defined) followed by a binary data packet terminated with ZCRCW.  The
+data packet contains the null terminated Attn sequence, maximum
+length 32 bytes including the terminating null.
+
+11.4  ZACK
+
+Acknowedgement to ZSINIT header packet, ZCHALLENGE header packet, or
+ZCRCW data packet.  ZP0 to ZP3 contain file offset.  Response to
+ZCHALLENGE contains the same 32 bits as received.
+
+11.5  ZFILE
+
+This packet denotes the beginning of a file transmission attempt.
+ZF0, ZF1, and ZF2 may contain options.  A value of 0 in each of these
+bytes implies no special treatment.  If options are specified to the
+reciever, they override options specified to the sender with the
+exception of the ZCBIN option, which overrides any other Conversion
+Option.
+
+
+11.5.1  ZF0: Conversion Option
+If the receiver does not recognize the Conversion Option, an
+application dependent default conversion may apply.
+
+ZCBIN "Binary" transfer - inhibit conversion unconditionally
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       16
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       17
+
+
+
+ZCNL Convert received end of line to local end of line convention.
+     The suported end line conventions are CR/LF (most ASCII based
+     operating systems except Unix and Macintosh), and NL (Unix).
+     Neither of these two end of line conventions violate the
+     permissible ASCII definitions for Carriage Return and Line
+     Feed/New Line.
+
+ZCRECOV Recover interrupted file transfer; start transfer at location
+     corresponding to the receiver's end of file.  This option does
+     not apply if the source file is shorter.  Files that have been
+     converted (e.g., ZCNL) or subject to a single ended Transport
+     Option cannot have their transfers recovered.
+
+11.5.2  ZF1: Management Option
+If the receiver does not recognize the Management Option, the file
+should be transferred normally.
+
+ZMNEW Compare the source and destination files.  Transfer file if
+     source newer or different length
+
+ZMCRC Compare the source and destination files.  Transfer if
+     different file length or CRC
+
+ZMAPND Append source file contents to existing destination file (if
+     any)
+
+ZMCLOB Replace existing destination file (if any)
+
+ZTSPARS Special processing for sparse file; each file segment is
+     transmitted as a separate frame, where the frames are not
+     necessarily contiguous.
+
+11.5.3  ZF2: Transport Option
+If the receiver does not implement the particular transport option,
+the file is copied without conversion for later processing.
+
+ZTLZW Lempel-Ziv compression.  Transmitted data will be identical to
+     that produced by compress 4.0 operating on a computer with VAX
+     byte ordering, using 12 bit encoding.
+
+ZTCRYPT Encryption.  An initial null terminated string identifies the
+     key.  Details to be determined.
+
+ZTRLE Run Length encoding Details to be determined.
+
+A ZCRCW data packet follows with file name, file length, modification
+date, and other information described in a later chapter.
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       17
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       18
+
+
+
+11.6  ZSKIP
+
+Sent by the receiver in response to ZFILE, makes the sender skip to
+the next file.
+
+11.7  ZNAK
+
+Indicates last packet header was garbled.  (See also ZRPOS).
+
+11.8  ZABORT
+
+Sent by receiver to terminate batch file transfers when requested by
+the user.  Sender initiates a ZFIN sequence.[1]
+
+11.9  ZFIN
+
+Sent by sending program to terminate a ZMODEM session.  Receiver
+responds with ZFIN.
+
+11.10  ZRPOS
+
+Sent by receiver to force file transfer to resume at file offset
+given in ZP0...ZP3.
+
+11.11  ZDATA
+
+ZP0...ZP3 contain file offset.  One or more data packets follow.
+
+11.12  ZEOF
+
+Sender reports End of File.  ZP0...ZP3 contain the ending file
+offset.
+
+11.13  ZFERR
+
+Error in reading or writing file, protocol equivalent to ZABORT.
+
+11.14  ZCRC
+
+Request (receiver) and response (sender) for file CRC.  ZP0 and ZP1
+contain 16 bit file CRC.
+
+
+
+
+
+
+__________
+
+ 1. Or ZCOMPL in case of server mode.
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       18
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       19
+
+
+
+11.15  ZCHALLENGE
+
+Request to echo a random number in ZP0...ZP3 in a ZACK frame.  Sent
+by the receiving program to the sending program to verify that it is
+connected to an operating program, and was not activated by spurious
+data or a Trojan Horse message.
+
+11.16  ZCOMPL
+
+Request now completed.
+
+11.17  ZCAN
+
+This is a pseudo frame type returned by gethdr() in response to a
+Cancel sequence.
+
+11.18  ZFREECNT
+
+Sending program requests a ZACK frame with ZP0...ZP3 containing the
+number of free bytes on the current file system.  A value of 0
+represents an indefinite amount of free space.
+
+11.19  ZCOMMAND
+
+ZCOMMAND is only sent as a binary header packet.  ZP0...ZP2 contain a
+unique cardinal number to differentiate this command from other
+commands[2].  ZF0 contains 0 or ZCACK1.
+
+
+A ZCRCW data packet follows, with the ASCII text command string
+terminated with a NULL character.  If the command is intended to be
+executed by the operating system hosting the receiving program (e.g.,
+"shell escape"), it must have "!" as the first character.  Otherwise
+the command is meant to be executed by the application program which
+received the command.
+
+If ZF0 contained ZCACK1, the receiver immediately responds with a
+ZCOMPL header.  Otherwise, the receiver responds with a ZCOMPL header
+when the operation is completed.
+
+The exit status of the completed command is stored in ZP0...ZP3 (0 if
+ZCACK1).  A 0 exit status implies nominal completion of the command.
+
+If the command caused a file to be transmitted, the command sender
+will see a ZRQINIT frame from the other computer attempting to send
+
+
+__________
+
+ 2. Currently unused.
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       19
+
+
+
+
+
+
+
+Chapter 11              rev051486 Printed 5-16-86                       20
+
+
+
+data.
+
+The sender examines ZF0 of the received ZRQINIT packet to determine
+it is not an echo of its own ZRQINIT packet.  It is illegal for the
+sending program to command the receiving program to send a command.
+
+
+
+12.  TRANSACTION EXAMPLE
+
+12.1  A simple file transfer
+
+A simple transaction, one file, no errors, no CHALLENGE, overlapped
+I/O:
+
+Sender          Receiver
+
+"rz\r"
+ZRQINIT(0)
+                ZRINIT
+ZFILE
+                ZRPOS
+ZDATA data ...
+ZEOF
+                ZRINIT
+ZFIN
+                ZFIN
+OO
+
+
+12.2  Challenge and Command Download
+
+
+Sender          Receiver
+
+"rz\r"
+ZRQINIT(ZCOMMAND)
+                ZCHALLENGE(rnd)
+ZACK(same-rnd)
+                ZRINIT
+ZCOMMAND
+                (Perform Command)
+                ZCOMPL
+ZFIN
+                ZFIN
+OO
+
+
+
+
+
+
+
+
+Chapter 13              rev051486 Printed 5-16-86                       20
+
+
+
+
+
+
+
+Chapter 13              rev051486 Printed 5-16-86                       21
+
+
+
+13.  ZFILE FRAME FILE INFORMATION
+
+ZMODEM sends the same file information with the ZFILE frame data that
+YMODEM Batch sends in its block 0.
+
+N.B.: Only the pathname (file name) part is
s required for batch
+transfers.
+
+Pathname The pathname (conventionally, the file name) is sent as a
+     null terminated ASCII string.  This is the filename format used
+     by the handle oriented MSDOS(TM) functions and C library fopen
+     functions.  An assembly language example follows:
+                           DB      'foo.bar',0
+     No spaces are included in the pathname.  Normally only the file
+     name stem (no directory prefix) is transmitted unless the sender
+     has selected YAM's f option to send the full relative pathname.
+     The source drive designator (A:, B:, etc.) is not sent.
+
+     Filename Considerations:
+
+        + File names should be translated to lower case unless the
+          sending system supports upper/lower case file names.  This
+          is a convenience for users of systems (such as Unix) which
+          store filenames in upper and lower case.
+
+        + The receiver should accommodate file names in lower and
+          upper case.
+
+        + The rb(1) program on Unix systems normally translates the
+          filename to lower case unless one or more letters in the
+          filename are already in lower case.
+
+        + When transmitting files between different operating
+          systems, file names must be acceptable to both the sender
+          and receiving operating systems.
+
+     If directories are included, they are delimited by /; i.e.,
+     "subdir/foo" is acceptable, "subdir\foo" is not.
+
+Length The file length and each of the succeeding fields are
+     optional.[1] The length field is stored as a decimal string
+     counting the number of data bytes in the file.
+
+     With ZMODEM, the receiver uses the file length only for display
+     (progress reporting) purposes; the actual length is determined
+
+
+__________
+
+ 1. Fields may not be skipped.
+
+
+
+
+Chapter 13              rev051486 Printed 5-16-86                       21
+
+
+
+
+
+
+
+Chapter 13              rev051486 Printed 5-16-86                       22
+
+
+
+     by the data transfer.
+
+Modification Date A single space separates the modification date from
+     the file length.
+
+     The mod date is optional, and the filename and length may be
+     sent without requiring the mod date to be sent.
+
+     The mod date is sent as an octal number giving the time the
+     contents of the file were last changed measured in seconds from
+     Jan 1 1970 Universal Coordinated Time (GMT).  A date of 0
+     implies the modification date is unknown and should be left as
+     the date the file is received.
+
+     This standard format was chosen to eliminate ambiguities arising
+     from transfers between different time zones.
+
+     Two Microsoft blunders complicate the use of modification dates
+     in file transfers with MSDOS(TM) systems.  The first is the lack
+     of timezone standardization in MS-DOS.  A file's creation time
+     can not be known unless the timezone of the system that wrote
+     the file[2] is known.  Unix solved this problem (for planet
+     Earth, anyway) by stamping files with Universal Time (GMT).
+     Microsoft would have to include the timezone of origin in the
+     directory entries, but does not.  Professional-YAM gets around
+     this problem by using the z parameter which is set to the number
+     of minutes local time lags GMT.  For files known to originate
+     from a different timezone, the -zT option may be used to specify
+     T as the timezone for an individual file transfer.
+
+     The second problem is the lack of a separate file creation date
+     in DOS.  Since some backup schemes used with DOS rely on the
+     file creation date to select files to be copied to the archive,
+     back-dating the file modification date could interfere with the
+     safety of the transferred files.  For this reason,
+     Professional-YAM does not modify the date of received files with
+     the header information unless the d parameter is non zero.
+
+
+Mode A single space separates the file mode from the modification
+     date.  The file mode is stored as an octal string.  Unless the
+     file originated from a Unix system, the file mode is set to 0.
+     rb(1) checks the file mode for the 0x8000 bit which indicates a
+     Unix type regular file.  Files with the 0x8000 bit set are
+     assumed to have been sent from another Unix (or similar) system
+
+
+__________
+
+ 2. Not necessarily that of the transmitting system!
+
+
+
+
+Chapter 13              rev051486 Printed 5-16-86                       22
+
+
+
+
+
+
+
+Chapter 13              rev051486 Printed 5-16-86                       23
+
+
+
+     which uses the same file conventions.  Such files are not
+     translated in any way.
+
+
+Serial Number A single space separates the serial number from the
+     file mode.  The serial number of the transmitting program is
+     stored as an octal string.  Programs which do not have a serial
+     number should omit this field, or set it to 0.  The receiver's
+     use of this field is optional.
+
+The file information is terminated by a null.  If only the pathname
+is sent, the pathname will be terminated by two nulls.  The length of
+the file information packet, including the trailing null, must not
+exceed 1024 bytes; a typical length is less than 64 bytes.
+
+
+14.  PERFORMANCE RESULTS
+
+14.1  Throughput
+
+Between two single task PC-XT computrers, on a Telenet link through
+the local Telenet, SuperKermit gave 72 ch/sec throughput at 1200
+baud.  YMODEM-k yielded 85 chars/sec, and ZMODEM provided 113 chat
+sec.  ZMODEM was not measured, but would have given much less.
+
+14.2  Error Recovery
+
+Some tests of ZMODEM protocol performance have been made.  A PC-AT
+with SCO SYS V Xenix or DOS 3.1 was connected to a PC with DOS 2.1
+either directly at 9600 bps or with unbuffered dial-up 1200 bps
+modems.  The ZMODEM software was configured to use 1024 byte packet
+lengths above 2400 bps, 256 otherwise.
+
+Because no time delays are necessary in normal file transfers, per
+file negotiations are much faster than with YMODEM, the only observed
+impidiment being the time required by the program(s) to update
+logging files.
+
+During a file transfer, a short line hit seen by the receiver usually
+induces a CRC error.  The interrupt packet is usually seen by the
+sender before the next packet is sent, and the resultant loss of data
+throughput averages about half a packet.  At 1200 bps this is would
+be about .75 second lost per hit.  At 10-5 error rate, this would
+degrade throughput by about 9 per cent.  The throughput degradation
+increases with the channel delay, as the packets in transit through
+the channel are discarded on error.
+
+A longer noise burst that affects both the receiver and the sender's
+reception of the interrupt packet usually causes the sender to remain
+silent until the receiver times out in 10 seconds.  If the round trip
+channel delay exceeds the receiver's 10 second timeout, recovery from
+
+
+
+Chapter 14              rev051486 Printed 5-16-86                       23
+
+
+
+
+
+
+
+Chapter 14              rev051486 Printed 5-16-86                       24
+
+
+
+this type of error may become difficult.
+
+Noise affecting only the sender is usually ignored, with one common
+exception.  Spurious XOFF characters generated by noise stop the
+sender until the receiver times out and sends an interrupt packet
+which concludes with an XON.
+
+In summation, ZMODEM performance in the presence of errors resembles
+that of X.PC and SuperKermit.  Short bursts cause minimuml data loss.
+Long bursts (such as pulse dialing noises) often require a timeout
+error to restore the flow of data.
+
+
+15.  PACKET SWITCHED NETWORK CONSIDERATIONS
+
+Flow control is necessary for printing messages and directories, and
+for streaming file transfer protocols including Kermit Sliding
+Windows and ZMODEM.  A non transparent flow control is incompatible
+with XMODEM and YMODEM transfers.  XMODEM and YMODEM protocols
+require complete transparency of all 256 8 bit codes to operate
+properly.
+
+The most desireable flow control (when X.25 or hardware CTS is
+unavailable) does not "eat" any characters at all.  When the PAD's
+buffer almost fills up, an XOFF should be emitted.  When the buffer
+is no longer nearly full, send an XON.  Otherwise, the network should
+neither generate nor eat XON or XOFF control characters.
+
+On Telenet, this can be met by setting CCIT X3 5:1 and 12:0 at both
+ends of the network.  For best throughput, parameter 64 (advance ACK)
+should be set to something like 4.  Packets should be sent when the
+packet is a full 128 bytes, or after a moderate delay (3:0,4:10,6:0).
+
+For YMODEM, PAD buffering should guarantee that a minimum of 1040
+characters can be sent in a burst without loss of data or generation
+of flow control characters.  Failure to provide this buffering will
+generate excessive retries with YMODEM.
+
+                  Figure 4.  Flow Control Compatibility
+
+         Connectivity            Interactive   XMODEM   KERMIT   ZMODEM
+
+Direct Connection                YES           YES      YES      YES
+Network, no flow control         NO            YES      (1)      (1)
+Network, transparent f.c.        YES           YES      YES      YES
+Network, semi-transparent f.c.   YES           NO       YES      YES
+Network, 7 bit                   YES           NO       YES(2)   NO(3)
+
+(1) Cannot operate in streaming mode.  Kermit is very slow because of
+96 byte max packet size.  ZMODEM can adjust burst length to maximum
+for faster transfers.
+
+
+
+Chapter 15              rev051486 Printed 5-16-86                       24
+
+
+
+
+
+
+
+Chapter 15              rev051486 Printed 5-16-86                       25
+
+
+
+(2) Parity bits must be encoded, slowing binary transfers.
+
+(3) Extension possible for encoding data to 7 bits.
+
+
+
+16.  PERFORMANCE COMPARISION TABLES
+
+
+"Round Trip Delay Time" includes the time for the last byte in a
+packet to propagate through the operating systems and network to the
+receiver, plus the time for the receiver's response to that packet to
+propogate back to the sender.
+
+The figures shown below are calculated for round trip delay times of
+40 milliseconds and 5 seconds.  Shift registers in the two computers
+and a pair of 212 modems generate a round trip delay time on the
+order of 40 milliseconds.  Operation with busy timesharing computers
+and networks can easily generate round trip delays of five seconds.
+Because the round trip delays cause visible interruptions of data
+transfer when using XMODEM protocol, the subjective effect of these
+delays is greatly exaggerated, especially when the user is paying for
+connect time.
+
+A 102400 byte binary file with randomly distributed codes is sent at
+1200 bps 8 data bits, 1 stop bit.  The calculations assume no
+transmission errors.  For each of the protocols, only the per file
+functions are considered.  Processor and I/O overhead are not
+included.  YM-k refers to YMODEM with 1024 byte packets.  YM-g refers
+to the YMODEM "g" option.  ZMODEM uses 256 byte packets for this
+example.  SuperKermit uses maximum packet size, 8 bit transparent
+transmission, no run length compression.
+
+For comparison, a straight "dump" of the file contents with no file
+management or error checking takes 853 seconds.
+
+                 Figure 5.  Protocol Overhead Information
+
+      Protocol          XMODEM   YM-k    YM-g   ZMODEM   S-Kermit
+
+Protocol Round Trips    803      103     5      5        5
+Trip Time at 40ms       32s      4s      0      0        0
+Trip Time at 5s         4015s    515s    25s    25s      25
+
+Overhead Characters     4803     603     503    3600     38280
+
+Transfer Time at 0s     893s     858s    857s   883s     1172s
+Transfer Time at 40ms   925s     862s    857s   883s     1172s
+Transfer Time at 5s     5761s    1373s   882s   918s     1197s
+
+
+
+
+
+Chapter 16              rev051486 Printed 5-16-86                       25
+
+
+
+
+
+
+
+Chapter 16              rev051486 Printed 5-16-86                       26
+
+
+
+                 Figure 6.  Transmission Time Comparision
+                        (5 Second Round Trip)
+
+************************************************** XMODEM
+************ YMODEM-K
+********** SuperKermit (Sliding Windows)
+******* YMODEM-G
+******* ZMODEM
+
+               Figure 7.  Y/ZMODEM Header Information usage
+
+
+  Program     Batch   Length   Date   Mode   S/N   YMODEM-g   ZMODEM
+ Unix rb/sb   yes     yes      yes    yes    no    sb only    no
+ Unix rz/sz   yes     yes      yes    yes    no    sz only    yes
+ VMS rb/sb    yes     yes      no     no     no    no         no
+ Pro-YAM      yes     yes      yes    no     yes   yes        yes
+ CP/M YAM     yes     no       no     no     no    no         no
+ KMD/IMP      yes     yes-     no     no     no    no         no
+ MEX          no      no       no     no     no    no         no
+
+
+17.  MORE INFORMATION
+
+More information may be obtained by calling Telegodzilla at
+503-621-3746.
+
+UUCP sites can obtain the nroff/troff source to this file with
+              uucp omen!/usr/caf/public/zmodem.mm /tmp
+A continually updated list of available files is stored in
+/usr/spool/uucppublic/FILES.
+
+The following L.sys line calls site "omen" yia UUCP.  Telegodzilla
+uses Pro-YAM in host operation.
+
+In response to "Name Please:" uucico gives the Pro-YAM "link" command
+as a user name.  The password (Giznoid) controls access to the Xenix
+system connected to the IBM PC's other serial port.  Communications
+between Pro-YAM and Xenix use 9600 bps; YAM converts this to the
+caller's speed.
+
+Finally, the calling uucico logs in as uucp.
+
+ omen Any ACU 1200 1-503-621-3746 e:--e: link d: Giznoid n:--n: uucp
+
+
+
+
+
+
+
+
+
+
+Chapter 18              rev051486 Printed 5-16-86                       26
+
+
+
+
+
+
+
+Chapter 18              rev051486 Printed 5-16-86                       27
+
+
+
+18.  ZMODEM PROGRAMS
+
+A demonstration version of Professional-YAM is available as
+YAMDEMO.ARC on TeleGodzilla..  This file must be unpacked with the
+"ARC" program, version 5 or later.  A copy of ARC is available as
+"ARC.EXE" or "ARC510.COM" on TeleGodzilla.
+
+
+This may be used to test ZMODEM and YMODEM implementations.  A
+flash-up tree structured help file and processor are provided in
+YAMHELP.LQR.
+
+
+
+19.  YMODEM PROGRAMS
+
+Unix programs supporting the YMODEM protocol are available on
+Telegodzilla in the "upgrade" subdirectory as RBSB.SHQ (a SQueezed
+shell archive).  Most Unix like systems are supported, including V7,
+Sys III, 4.2 BSD, SYS V, Idris, Coherent, and Regulus.
+
+A version for VAX-VMS is available in VRBSB.SHQ, in the same
+directory.
+
+Irv Hoff has added YMODEM 1k packets and YMODEM batch transfers to
+the KMD and IMP series programs, which replace the XMODEM and
+MODEM7/MDM7xx series respectively.  Overlays are available for a wide
+variety of CP/M systems.
+
+Many other programs, including MEX and MEX-PC also support some of
+the YMODEM extensions.
+
+Questions about YMODEM, the Professional-YAM communications program,
+and requests for evaluation copies may be directed to:
+
+     Chuck Forsberg
+     Omen Technology Inc
+     17505-V Sauvie Island Road
+     Portland Oregon 97231
+     Voice: 503-621-3406
+     Modem (Telegodzilla): 503-621-3746
+     Usenet: ...!tektronix!reed!omen!caf
+     Compuserve: 70715,131
+     Source: TCE022
+
+                                  Yours very truly,
+
+
+
+
+
+
+
+
+Chapter 19              rev051486 Printed 5-16-86                       27
+
+
+
+
+
+
+
+
+
+
+
+                              CONTENTS
+
+
+ 1.  INTENDED AUDIENCE................................................   2
+
+ 2.  ACKNOWLEDGMENTS..................................................   2
+
+ 3.  RELATED DOCUMENTS................................................   2
+
+ 4.  ROSETTA STONE....................................................   2
+
+ 5.  WHY DEVELOP ZMODEM?..............................................   3
+
+ 6.  ZMODEM Protocol Design Criteria..................................   5
+     6.1    Ease of Use...............................................   5
+     6.2    Throughput................................................   5
+     6.3    Integrity and Robustness..................................   6
+     6.4    Ease of Implementation....................................   6
+
+ 7.  ZMODEM BASICS....................................................   6
+     7.1    Packetization.............................................   7
+     7.2    Link Escape Encoding......................................   7
+     7.3    Header Packet Information.................................   8
+     7.4    Binary Header Packet......................................   9
+     7.5    HEX Header Packet.........................................   9
+     7.6    Binary Data Packets.......................................  10
+     7.7    ASCII Encoded Data Packet.................................  10
+
+ 8.  PROTOCOL TRANSACTION OVERVIEW....................................  10
+     8.1    Session Cancel Packet.....................................  13
+
+ 9.  ZMODEM STREAMING TECHNIQUES......................................  14
+     9.1    Full Streaming with Sampling..............................  14
+     9.2    Full Streaming with Interrupt.............................  14
+     9.3    Full Streaming with a Sliding Window......................  15
+     9.4    No Streaming..............................................  15
+
+10.  ATTENTION SEQUENCE...............................................  15
+
+11.  PACKET/FRAME TYPES...............................................  15
+     11.1   ZRQINIT...................................................  16
+     11.2   ZRINIT....................................................  16
+     11.3   ZSINIT....................................................  16
+     11.4   ZACK......................................................  16
+     11.5   ZFILE.....................................................  16
+     11.6   ZSKIP.....................................................  18
+     11.7   ZNAK......................................................  18
+     11.8   ZABORT....................................................  18
+     11.9   ZFIN......................................................  18
+     11.10  ZRPOS.....................................................  18
+     11.11  ZDATA.....................................................  18
+
+
+
+                                  - i -
+
+
+
+
+
+
+
+
+
+
+
+     11.12  ZEOF......................................................  18
+     11.13  ZFERR.....................................................  18
+     11.14  ZCRC......................................................  18
+     11.15  ZCHALLENGE................................................  19
+     11.16  ZCOMPL....................................................  19
+     11.17  ZCAN......................................................  19
+     11.18  ZFREECNT..................................................  19
+     11.19  ZCOMMAND..................................................  19
+
+12.  TRANSACTION EXAMPLE..............................................  20
+     12.1   A simple file transfer....................................  20
+     12.2   Challenge and Command Download............................  20
+
+13.  ZFILE FRAME FILE INFORMATION.....................................  21
+
+14.  PERFORMANCE RESULTS..............................................  23
+     14.1   Throughput................................................  23
+     14.2   Error Recovery............................................  23
+
+15.  PACKET SWITCHED NETWORK CONSIDERATIONS...........................  24
+
+16.  PERFORMANCE COMPARISION TABLES...................................  25
+
+17.  MORE INFORMATION.................................................  26
+
+18.  ZMODEM PROGRAMS..................................................  27
+
+19.  YMODEM PROGRAMS..................................................  27
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                  - ii -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                             LIST OF FIGURES
+
+
+Figure 1.  Order of Bytes in Header Packet............................   8
+
+Figure 2.  Binary Header Packet.......................................   9
+
+Figure 3.  HEX Header Packet..........................................  10
+
+Figure 4.  Flow Control Compatibility.................................  24
+
+Figure 5.  Protocol Overhead Information..............................  25
+
+Figure 6.  Transmission Time Comparision..............................  26
+
+Figure 7.  Y/ZMODEM Header Information usage..........................  26
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                 - iii -
+
+
+
+
+
+
+
+
+
+     The ZMODEM Asynchronous Inter Application File Transfer Protocol
+
+                              Chuck Forsberg
+
+                           Omen Technology Inc
+
+
+                                 ABSTRACT
+
+
+
+The ZMODEM file transfer protocol greatly simplifies file transfers
+compared to XMODEM.  In addition to supporting a transparent user
+interface, ZMODEM provides Personal Computer and other users an efficient,
+accurate, robust file transfer method.
+
+ZMODEM provides especially efficient file transfers with timesharing
+systems, satellite relays, and wide area packet switched networks.  A
+choice of buffering and windowing modes allow ZMODEM to operate
+efficiently on systems that cannot support some other streaming protocols.
+
+ZMODEM provides advanced file management features including AutoDownload,
+remote file compare, aborted transfer recovery, selective file transfers,
+and security verified command downloading.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Ös×�[ÀéÐ Eš¸Ö0b€su@;w÷`R0—0í°õ
+Xv{u‹ P
+–e÷Qç�Bm
+˜ ‡“†÷Їè0Òh¸+0
à[°ÝЀ• 	‘0	s0O0€€ày8ˆ`Y8í0O°¡è¤è§ÈPŠ€ŠõcXë�°0sÿPPhþ€Oµû;>·ÕÀ†ë�ÙP‡„]�İ÷p0Œ€j— à Ç û >Š�Šàºt	šF
â(ÀP	ÛH%upNàj°&k`
Ç�€@ï°T°Õ°Ê Ÿ¶AEP]Â
è  ‘rð6E%wÐrpöpA$ë@XÐ@r ëÀI’&‰’ÏÀ’ƒp
o¿@%FÀ†ÎèsŠ�
éÐ
+
+f‘^ ‘s
+‘F
+ Š`èÄæ€•pgt	Y‘‰‘ý3),`Æ H'0’%y’rð+i‘�–0¹À†€P–ÐÐ
Ð8©“l(Ò€?i•B�•[i‘^©‘9–ÂDgé’jÉ–,9‘où’rð<sكИw™—{Ù—€`¡ÐE—��M ‰@d‰P`�èˆP
+þÀX}€¶Y~€‰pcÆÀZ0ÓˆX ³Ù\Õå4D©•è ‘é9éuP9€œ´9;¹YiÄup¾€ €�ʹXÂæ�˜é`b†ð©3$Ѐ†@eiÂIè€î £DE€ €L<ðt(H3€d ,ð˜�Á…�Tp‰À†ˆàƒªš0ª4¶ € àÉ
0ŒØÎë0
)ú¢à‰„È6Š£¿P]±R¡˜H
ç
Ò Ò�÷°ªIup„
é�	rDuÐA\PŠ@ Z[´ð˜‚fªé€
+XöX¦
´4K£§ŠÀ ÉPÁ°§¾\=Ð}ð
=ÿàÝ@`¦`¯õZ0ˆ
‹@@ ¿d‹¦™:t€Y©P”é
©šb©ªr � T"p`ÃD@Ÿƒ�«ïÔ)Ð��3ƒâ÷A0	«°ð
+³Ãªö ä€ݰð ­xÀë°z‹…nzªZ¹ª®Š®.°àìA€ üà¡À°¬Íºèê·ú

+ 107 - 0
components/utilities/ZMODEM/ZMODEM.H

@@ -0,0 +1,107 @@
+/*
+ *   Z M O D E M . H     Manifest constants for ZMODEM
+ *    application to application file transfer protocol
+ *    5-16-86  Chuck Forsberg Omen Technology Inc
+ */
+#define ZPAD '*'	/* 052 Padding character begins frames */
+#define ZDLE 030	/* Ctrl-X Zmodem escape - `ala BISYNC DLE */
+#define ZDLEE (ZDLE^0100)	/* Escaped ZDLE as transmitted */
+#define ZBIN 'A'	/* Binary frame indicator */
+#define ZHEX 'B'	/* HEX frame indicator */
+
+/* Frame types (see array "frametypes" in zm.c) */
+#define ZRQINIT	0	/* Request receive init */
+#define ZRINIT	1	/* Receive init */
+#define ZSINIT 2	/* Send init sequence (optional) */
+#define ZACK 3		/* ACK to above */
+#define ZFILE 4		/* File name from sender */
+#define ZSKIP 5		/* To sender: skip this file */
+#define ZNAK 6		/* Last packet was garbled */
+#define ZABORT 7	/* Abort batch transfers */
+#define ZFIN 8		/* Finish session */
+#define ZRPOS 9		/* Resume data trans at this position */
+#define ZDATA 10	/* Data packet(s) follow */
+#define ZEOF 11		/* End of file */
+#define ZFERR 12	/* Fatal Read or Write error Detected */
+#define ZCRC 13		/* Request for file CRC and response */
+#define ZCHALLENGE 14	/* Receiver's Challenge */
+#define ZCOMPL 15	/* Request is complete */
+#define ZCAN 16		/* Other end canned session with CAN-CAN */
+#define ZFREECNT 17	/* Request for free bytes on filesystem */
+#define ZCOMMAND 18	/* Command from sending program */
+
+/* ZDLE sequences */
+#define ZCRCE 'h'	/* CRC next, frame ends, header packet follows */
+#define ZCRCG 'i'	/* CRC next, frame continues nonstop */
+#define ZCRCQ 'j'	/* CRC next, frame continues, ZACK expected */
+#define ZCRCW 'k'	/* CRC next, ZACK expected, end of frame */
+#define ZRUB0 'l'	/* Translate to rubout 0177 */
+#define ZRUB1 'm'	/* Translate to rubout 0377 */
+
+/* zdlread return values (internal) */
+/* -1 is general error, -2 is timeout */
+#define GOTOR 0400
+#define GOTCRCE (ZCRCE|GOTOR)	/* ZDLE-ZCRCE received */
+#define GOTCRCG (ZCRCG|GOTOR)	/* ZDLE-ZCRCG received */
+#define GOTCRCQ (ZCRCQ|GOTOR)	/* ZDLE-ZCRCQ received */
+#define GOTCRCW (ZCRCW|GOTOR)	/* ZDLE-ZCRCW received */
+#define GOTCAN	(GOTOR|030)	/* CAN-CAN seen */
+
+/* Byte positions within header array */
+#define ZF0	3	/* First flags byte */
+#define ZF1	2
+#define ZF2	1
+#define ZF3	0
+#define ZP0	0	/* Low order 8 bits of position */
+#define ZP1	1
+#define ZP2	2
+#define ZP3	3	/* High order 8 bits of file position */
+
+/* Bit Masks for ZRINIT flags byte ZF0 */
+#define CANFDX	01	/* Rx can send and receive true FDX */
+#define CANOVIO	02	/* Rx can receive data during disk I/O */
+#define CANBRK	04	/* Rx can send a break signal */
+#define CANCRY	010	/* Receiver can decrypt */
+#define CANLZW	020	/* Receiver can uncompress */
+
+/* Parameters for ZSINIT frame */
+#define ZATTNLEN 32	/* Max length of attention string */
+
+/* Parameters for ZFILE frame */
+/* Conversion options one of these in ZF0 */
+#define ZCBIN	1	/* Binary transfer - inhibit conversion */
+#define ZCNL	2	/* Convert NL to local end of line convention */
+#define ZCRESUM	3	/* Resume interrupted file transfer */
+/* Management options, one of these in ZF1 */
+#define ZMNEW	1	/* Transfer if source newer or different length */
+#define ZMCRC	2	/* Transfer if different file CRC or length */
+#define ZMAPND	3	/* Append contents to existing file (if any) */
+#define ZMCLOB	4	/* Replace existing file */
+#define ZMSPARS	5	/* Encoding for sparse file */
+/* Transport options, one of these in ZF2 */
+#define ZTLZW	1	/* Lempel-Ziv compression */
+#define ZTCRYPT	2	/* Encryption */
+#define ZTRLE	3	/* Run Length encoding */
+
+/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */
+#define ZCACK1	1	/* Acknowledge, then do command */
+
+long int rclhdr(char *hdr);
+
+/* Globals used by ZMODEM functions */
+int Rxframeind;		/* ZBIN or ZHEX indicates type of frame received */
+int Rxtype;		/* Type of header received */
+int Rxcount;		/* Count of data bytes received */
+extern int Rxtimeout;	/* Tenths of seconds to wait for something */
+char Rxhdr[4];		/* Received header */
+char Txhdr[4];		/* Transmitted header */
+long Rxpos;		/* Received file position */
+long Txpos;		/* Transmitted file position */
+char Attn[ZATTNLEN+1];	/* Attention string rx sends to tx on err */
+
+extern rt_device_t _console_device;
+extern struct finsh_shell* shell;
+#define zwrite(x1)          rt_device_write(_console_device, 0, &x1, 1)
+#define zread(x1,x2,x3,x4)  rt_device_read (x1,x2,x3,x4)
+
+extern void vfile(const char *fmt,...);