1550 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1550 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #define VERSION "2.03 05-17-88"
 | |
| #define PUBDIR "/usr/spool/uucppublic"
 | |
| 
 | |
| /*% cc -compat -M2 -Ox -K -i -DMD -DOMEN % -o rz; size rz;
 | |
| <-xtx-*> cc386 -Ox -DMD -DOMEN -DSEGMENTS=8 rz.c -o $B/rz;  size $B/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;  ln rz rx			For either system
 | |
|  *
 | |
|  *	ln rz /usr/bin/rzrmail		For remote mail.  Make this the
 | |
|  *					login shell. rzrmail then calls
 | |
|  *					rmail(1) to deliver mail.
 | |
|  *
 | |
|  * To compile on VMS:
 | |
|  *
 | |
|  *	define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
 | |
|  *	cc rz.c
 | |
|  *	cc vvmodem.c
 | |
|  *	link rz,vvmodem
 | |
|  *	rz :== $disk:[username.subdir]rz.exe
 | |
|  *
 | |
|  *
 | |
|  *  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"  (Unix only)
 | |
|  *
 | |
|  *  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 
 | |
|  *
 | |
|  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
 | |
|  *  Byte Information Exchange.
 | |
|  *
 | |
|  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
 | |
|  *  doesn't work properly (even though it compiles without error!),
 | |
|  *
 | |
|  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
 | |
|  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
 | |
|  *
 | |
|  *  VMS flavor hacks begin with rz version 2.00
 | |
|  *
 | |
|  *  -DMD may be added to compiler command line to compile in
 | |
|  *    Directory-creating routines from Public Domain TAR by John Gilmore
 | |
|  *
 | |
|  *  HOWMANY may be tuned for best performance
 | |
|  *
 | |
|  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
 | |
|  */
 | |
| 
 | |
| #include <sys/types.h>
 | |
| 
 | |
| #ifdef vax11c
 | |
| #include <types.h>
 | |
| #include <stat.h>
 | |
| #define LOGFILE "rzlog.tmp"
 | |
| #define OS "VMS"
 | |
| #define BUFREAD
 | |
| extern int errno;
 | |
| #define SS_NORMAL SS$_NORMAL
 | |
| #else
 | |
| /* Not vax11c */
 | |
| #define SS_NORMAL 0
 | |
| #define LOGFILE "/tmp/rzlog"
 | |
| #endif
 | |
| 
 | |
| #include <time.h>
 | |
| #include <ctype.h>
 | |
| #include <errno.h>
 | |
| #include <signal.h>
 | |
| #include <setjmp.h>
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <utime.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #define OK 0
 | |
| #define FALSE 0
 | |
| #define TRUE 1
 | |
| #undef ERROR
 | |
| #define ERROR (-1)
 | |
| 
 | |
| 
 | |
| _PROTOTYPE(long getfree , (void));
 | |
| _PROTOTYPE(void alrm , (int sig ));
 | |
| _PROTOTYPE(int main , (int argc , char *argv []));
 | |
| _PROTOTYPE(int usage , (void));
 | |
| _PROTOTYPE(int wcreceive , (int argc , char **argp ));
 | |
| _PROTOTYPE(int wcrxpn , (char *rpn ));
 | |
| _PROTOTYPE(int wcrx , (void));
 | |
| _PROTOTYPE(int wcgetsec , (char *rxbuf , int maxtime ));
 | |
| _PROTOTYPE(int readline , (int timeout ));
 | |
| _PROTOTYPE(void purgeline , (void));
 | |
| _PROTOTYPE(int procheader , (char *name ));
 | |
| _PROTOTYPE(int make_dirs , (char *pathname ));
 | |
| _PROTOTYPE(int makedir , (char *dpath , int dmode ));
 | |
| _PROTOTYPE(int putsec , (char *buf , int n ));
 | |
| _PROTOTYPE(void sendline , (int c ));
 | |
| _PROTOTYPE(void flushmo , (void));
 | |
| _PROTOTYPE(void uncaps , (char *s ));
 | |
| _PROTOTYPE(int IsAnyLower , (char *s ));
 | |
| _PROTOTYPE(char *substr , (char *s , char *t ));
 | |
| void zperr();
 | |
| _PROTOTYPE(void canit , (void));
 | |
| _PROTOTYPE(void report , (int sct ));
 | |
| _PROTOTYPE(void chkinvok , (char *s ));
 | |
| _PROTOTYPE(void checkpath , (char *name ));
 | |
| _PROTOTYPE(int tryz , (void));
 | |
| _PROTOTYPE(int rzfiles , (void));
 | |
| _PROTOTYPE(int rzfile , (void));
 | |
| _PROTOTYPE(void zmputs , (char *s ));
 | |
| _PROTOTYPE(int closeit , (void));
 | |
| _PROTOTYPE(void ackbibi , (void));
 | |
| _PROTOTYPE(void bttyout , (int c ));
 | |
| _PROTOTYPE(int sys2 , (char *s ));
 | |
| _PROTOTYPE(void exec2 , (char *s ));
 | |
| 
 | |
| /*
 | |
|  * Max value for HOWMANY is 255.
 | |
|  *   A larger value reduces system overhead but may evoke kernel bugs.
 | |
|  *   133 corresponds to an XMODEM/CRC sector
 | |
|  */
 | |
| #ifndef HOWMANY
 | |
| #define HOWMANY 133
 | |
| #endif
 | |
| 
 | |
| /* 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 RCDO (-3)
 | |
| #define ERRORMAX 5
 | |
| #define RETRYMAX 5
 | |
| #define WCEOT (-10)
 | |
| #define PATHLEN 257	/* ready for 4.2 bsd ? */
 | |
| #define UNIXFILE 0xF000	/* The S_IFMT file mask bit for stat */
 | |
| 
 | |
| int Zmodem=0;		/* ZMODEM protocol requested */
 | |
| int Nozmodem = 0;	/* If invoked as "rb" */
 | |
| unsigned Baudrate = 2400;
 | |
| 
 | |
| #ifdef vax11c
 | |
| #include "vrzsz.c"	/* most of the system dependent stuff here */
 | |
| #else
 | |
| #include "rbsb.c"	/* most of the system dependent stuff here */
 | |
| #endif
 | |
| 
 | |
| #include "crctab.c"
 | |
| 
 | |
| FILE *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 ... */
 | |
| }
 | |
| 
 | |
| 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 */
 | |
| #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 = HOWMANY;	/* 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 */
 | |
| int Filemode;		/* Unix style mode for incoming file */
 | |
| char Pathname[PATHLEN];
 | |
| char *Progname;		/* the name by which we were called */
 | |
| 
 | |
| int Batch=0;
 | |
| 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 Rxclob=FALSE;	/* Clobber existing file */
 | |
| int Rxbinary=FALSE;	/* receive all files in bin mode */
 | |
| int Rxascii=FALSE;	/* receive files in ascii (translate) mode */
 | |
| int Thisbinary;		/* current file is to be received in bin mode */
 | |
| int Blklen;		/* record length of received packets */
 | |
| 
 | |
| #ifdef SEGMENTS
 | |
| int chinseg = 0;	/* Number of characters received in this data seg */
 | |
| char secbuf[1+(SEGMENTS+1)*1024];
 | |
| #else
 | |
| char secbuf[1025];
 | |
| #endif
 | |
| 
 | |
| 
 | |
| char linbuf[HOWMANY];
 | |
| int Lleft=0;		/* number of characters in linbuf */
 | |
| time_t timep[2];
 | |
| char Lzmanag;		/* Local file management request */
 | |
| char zconv;		/* ZMODEM file conversion request */
 | |
| char zmanag;		/* ZMODEM file management request */
 | |
| char ztrans;		/* ZMODEM file transport request */
 | |
| int Zctlesc;		/* Encode control characters */
 | |
| int Zrwindow = 1400;	/* RX window size (controls garbage count) */
 | |
| 
 | |
| jmp_buf tohere;		/* For the interrupt on RX timeout */
 | |
| 
 | |
| #define xsendline(c) sendline(c)
 | |
| #include "zm.c"
 | |
| 
 | |
| int tryzhdrtype=ZRINIT;	/* Header type to send corresponding to Last rx close */
 | |
| 
 | |
| void alrm(sig)
 | |
| int sig;
 | |
| {
 | |
| 	longjmp(tohere, -1);
 | |
| }
 | |
| 
 | |
| /* called by signal interrupt or terminate to clean things up */
 | |
| void bibi(n)
 | |
| int n;
 | |
| {
 | |
| 	if (Zmodem)
 | |
| 		zmputs(Attn);
 | |
| 	canit(); mode(0);
 | |
| 	fprintf(stderr, "rz: caught signal %d; exiting\n", n);
 | |
| 	cucheck();
 | |
| 	exit(128+n);
 | |
| }
 | |
| 
 | |
| int main(argc, argv)
 | |
| int argc;
 | |
| char *argv[];
 | |
| {
 | |
| 	register char *cp;
 | |
| 	register npats;
 | |
| 	char *virgin, **patts;
 | |
| 	int exitcode = 0;
 | |
| 
 | |
| 	Rxtimeout = 100;
 | |
| 	setbuf(stderr, (char *)NULL);
 | |
| 	if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
 | |
| 		Restricted=TRUE;
 | |
| 
 | |
| 	from_cu();
 | |
| #ifdef vax11c
 | |
| 	Progname = virgin = "rz";
 | |
| #else
 | |
| 	chkinvok(virgin=argv[0]);	/* if called as [-]rzCOMMAND set flag */
 | |
| #endif
 | |
| 	npats = 0;
 | |
| 	while (--argc) {
 | |
| 		cp = *++argv;
 | |
| 		if (*cp == '-') {
 | |
| 			while( *++cp) {
 | |
| 				switch(*cp) {
 | |
| 				case '\\':
 | |
| 					 cp[1] = toupper(cp[1]);  continue;
 | |
| 				case '+':
 | |
| 					Lzmanag = ZMAPND; break;
 | |
| 				case 'a':
 | |
| 					Rxascii=TRUE;  break;
 | |
| 				case 'b':
 | |
| 					Rxbinary=TRUE; break;
 | |
| 				case 'c':
 | |
| 					Crcflg=TRUE; break;
 | |
| #ifndef vax11c
 | |
| 				case 'D':
 | |
| 					Nflag = TRUE; break;
 | |
| #endif
 | |
| 				case 'e':
 | |
| 					Zctlesc = 1; break;
 | |
| 				case 'p':
 | |
| 					Lzmanag = ZMPROT;  break;
 | |
| 				case 'q':
 | |
| 					Quiet=TRUE; Verbose=0; break;
 | |
| 				case 't':
 | |
| 					if (--argc < 1) {
 | |
| 						usage();
 | |
| 					}
 | |
| 					Rxtimeout = atoi(*++argv);
 | |
| 					if (Rxtimeout<10 || Rxtimeout>1000)
 | |
| 						usage();
 | |
| 					break;
 | |
| 				case 'w':
 | |
| 					if (--argc < 1) {
 | |
| 						usage();
 | |
| 					}
 | |
| 					Zrwindow = atoi(*++argv);
 | |
| 					break;
 | |
| 				case 'u':
 | |
| 					MakeLCPathname=FALSE; break;
 | |
| 				case 'v':
 | |
| 					++Verbose; break;
 | |
| 				case 'y':
 | |
| 					Rxclob=TRUE; break;
 | |
| 				default:
 | |
| 					usage();
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		else if ( !npats && argc>0) {
 | |
| 			if (argv[0][0]) {
 | |
| 				npats=argc;
 | |
| 				patts=argv;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if (npats > 1)
 | |
| 		usage();
 | |
| 	if (Batch && npats)
 | |
| 		usage();
 | |
| 	if (Verbose) {
 | |
| 		if (freopen(LOGFILE, "a", stderr)==NULL) {
 | |
| 			printf("Can't open log file %s\n",LOGFILE);
 | |
| 			exit(0200);
 | |
| 		}
 | |
| 		setbuf(stderr, (char *)NULL);
 | |
| 		fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
 | |
| 	}
 | |
| 	if (Fromcu && !Quiet) {
 | |
| 		if (Verbose == 0)
 | |
| 			Verbose = 2;
 | |
| 	}
 | |
| 	vfile("%s %s for %s\n", Progname, VERSION, OS);
 | |
| 	mode(1);
 | |
| 	if (signal(SIGINT, bibi) == SIG_IGN) {
 | |
| 		signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
 | |
| 	}
 | |
| 	else {
 | |
| 		signal(SIGINT, bibi); signal(SIGKILL, bibi);
 | |
| 	}
 | |
| 	signal(SIGTERM, bibi);
 | |
| 	if (wcreceive(npats, patts)==ERROR) {
 | |
| 		exitcode=0200;
 | |
| 		canit();
 | |
| 	}
 | |
| 	mode(0);
 | |
| 	vfile("exitcode = %d\n",exitcode);
 | |
| 	if (exitcode && !Zmodem)	/* bellow again with all thy might. */
 | |
| 		canit();
 | |
| 	if (exitcode)
 | |
| 		cucheck();
 | |
| 	if (Verbose) putc('\n', stderr);
 | |
| 	exit(exitcode ? exitcode:SS_NORMAL);
 | |
| }
 | |
| 
 | |
| 
 | |
| int usage()
 | |
| {
 | |
| 	cucheck();
 | |
| #ifdef vax11c
 | |
| 	fprintf(stderr,"Usage:	rz [-abeuvy]\n");
 | |
| #else
 | |
| 	fprintf(stderr,"Usage:	rz [-abeuvy]		(ZMODEM)\n");
 | |
| 	fprintf(stderr,"or	rb [-abuvy]		(YMODEM)\n");
 | |
| 	fprintf(stderr,"or	rx [-abcv] file	(XMODEM or XMODEM-1k)\n");
 | |
| #endif
 | |
| 	fprintf(stderr,"	  -a ASCII transfer (strip CR)\n");
 | |
| 	fprintf(stderr,"	  -b Binary transfer for all files\n");
 | |
| #ifndef vax11c
 | |
| 	fprintf(stderr,"	  -c Use 16 bit CRC	(XMODEM)\n");
 | |
| #endif
 | |
| 	fprintf(stderr,"	  -e Escape control characters	(ZMODEM)\n");
 | |
| 	fprintf(stderr,"	  -v Verbose more v's give more info\n");
 | |
| 	fprintf(stderr,"	  -y Yes, clobber existing file if any\n");
 | |
| 	fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
 | |
| 	  Progname, VERSION, OS);
 | |
| 	fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
 | |
| 	exit(SS_NORMAL);
 | |
| }
 | |
| /*
 | |
|  *  Debugging information output interface routine
 | |
|  */
 | |
| /* VARARGS1 */
 | |
| void vfile(f, a, b, c)
 | |
| register char *f,*a,*b,*c;
 | |
| 
 | |
| {
 | |
| 	if (Verbose > 2) {
 | |
| 		fprintf(stderr, f, a, b, c);
 | |
| 		fprintf(stderr, "\n");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Let's receive something already.
 | |
|  */
 | |
| 
 | |
| char *rbmsg =
 | |
| "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
 | |
| 
 | |
| int wcreceive(argc, argp)
 | |
| int argc;
 | |
| char **argp;
 | |
| {
 | |
| 	register c;
 | |
| 
 | |
| 	if (Batch || argc==0) {
 | |
| 		Crcflg=1;
 | |
| 		if ( !Quiet)
 | |
| 			fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
 | |
| 		if (c=tryz()) {
 | |
| 			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;
 | |
| 
 | |
| 		procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
 | |
| 		fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
 | |
| 		if ((fout=fopen(Pathname, "w")) == NULL)
 | |
| 			return ERROR;
 | |
| 		if (wcrx()==ERROR)
 | |
| 			goto fubar;
 | |
| 	}
 | |
| 	return OK;
 | |
| fubar:
 | |
| 	canit();
 | |
| #ifndef vax11c
 | |
| 	if (Topipe && fout) {
 | |
| 		pclose(fout);  return ERROR;
 | |
| 	}
 | |
| #endif
 | |
| 	if (fout)
 | |
| 		fclose(fout);
 | |
| #ifndef vax11c
 | |
| 	if (Restricted) {
 | |
| 		unlink(Pathname);
 | |
| 		fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
 | |
| 	}
 | |
| #endif
 | |
| 	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(rpn)
 | |
| char *rpn;	/* receive a pathname */
 | |
| {
 | |
| 	register 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) {
 | |
| 		if (c == WCEOT) {
 | |
| 			zperr( "Pathname fetch returned %d", c);
 | |
| 			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()
 | |
| {
 | |
| 	register int sectnum, sectcurr;
 | |
| 	register char sendchar;
 | |
| 	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) &0377)) {
 | |
| 			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&0377)) {
 | |
| 			zperr( "Received dup Sector");
 | |
| 			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 {
 | |
| 			zperr( "Sync Error");
 | |
| 			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(rxbuf, maxtime)
 | |
| char *rxbuf;
 | |
| int maxtime;
 | |
| {
 | |
| 	register checksum, wcj, firstch;
 | |
| 	register unsigned short oldcrc;
 | |
| 	register char *p;
 | |
| 	int sectcurr;
 | |
| 
 | |
| 	for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
 | |
| 
 | |
| 		if ((firstch=readline(maxtime))==STX) {
 | |
| 			Blklen=1024; goto get2;
 | |
| 		}
 | |
| 		if (firstch==SOH) {
 | |
| 			Blklen=128;
 | |
| get2:
 | |
| 			sectcurr=readline(1);
 | |
| 			if ((sectcurr+(oldcrc=readline(1)))==0377) {
 | |
| 				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)
 | |
| 						zperr( "CRC");
 | |
| 					else {
 | |
| 						Firstsec=FALSE;
 | |
| 						return sectcurr;
 | |
| 					}
 | |
| 				}
 | |
| 				else if (((checksum-firstch)&0377)==0) {
 | |
| 					Firstsec=FALSE;
 | |
| 					return sectcurr;
 | |
| 				}
 | |
| 				else
 | |
| 					zperr( "Checksum");
 | |
| 			}
 | |
| 			else
 | |
| 				zperr("Sector number garbled");
 | |
| 		}
 | |
| 		/* 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) {
 | |
| 				zperr( "Sender CANcelled");
 | |
| 				return ERROR;
 | |
| 			} else {
 | |
| 				Lastrx=CAN;
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (firstch==TIMEOUT) {
 | |
| 			if (Firstsec)
 | |
| 				goto humbug;
 | |
| bilge:
 | |
| 			zperr( "TIMEOUT");
 | |
| 		}
 | |
| 		else
 | |
| 			zperr( "Got 0%o sector header", 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;
 | |
| }
 | |
| 
 | |
| #ifndef vax11c
 | |
| /*
 | |
|  * 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(timeout)
 | |
| int timeout;
 | |
| {
 | |
| 	register n;
 | |
| 	static char *cdq;	/* pointer for removing chars from linbuf */
 | |
| 
 | |
| 	if (--Lleft >= 0) {
 | |
| 		if (Verbose > 8) {
 | |
| 			fprintf(stderr, "%02x ", *cdq&0377);
 | |
| 		}
 | |
| 		return (*cdq++ & 0377);
 | |
| 	}
 | |
| 	n = timeout/10;
 | |
| 	if (n < 2)
 | |
| 		n = 3;
 | |
| 	if (Verbose > 5)
 | |
| 		fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
 | |
| 		  n, Readnum);
 | |
| 	if (setjmp(tohere)) {
 | |
| #ifdef TIOCFLUSH
 | |
| /*		ioctl(iofd, TIOCFLUSH, 0); */
 | |
| #endif
 | |
| 		Lleft = 0;
 | |
| 		if (Verbose>1)
 | |
| 			fprintf(stderr, "Readline:TIMEOUT\n");
 | |
| 		return TIMEOUT;
 | |
| 	}
 | |
| 	signal(SIGALRM, alrm); alarm(n);
 | |
| 	Lleft=read(iofd, cdq=linbuf, Readnum);
 | |
| 	alarm(0);
 | |
| 	if (Verbose > 5) {
 | |
| 		fprintf(stderr, "Read returned %d bytes\n", Lleft);
 | |
| 	}
 | |
| 	if (Lleft < 1)
 | |
| 		return TIMEOUT;
 | |
| 	--Lleft;
 | |
| 	if (Verbose > 8) {
 | |
| 		fprintf(stderr, "%02x ", *cdq&0377);
 | |
| 	}
 | |
| 	return (*cdq++ & 0377);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Purge the modem input queue of all characters
 | |
|  */
 | |
| void purgeline()
 | |
| {
 | |
| 	Lleft = 0;
 | |
| #ifdef USG
 | |
| 	ioctl(iofd, TCFLSH, 0);
 | |
| #else
 | |
| 	lseek(iofd, 0L, 2);
 | |
| #endif
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Process incoming file information header
 | |
|  */
 | |
| int procheader(name)
 | |
| char *name;
 | |
| {
 | |
| 	register char *openmode, *p;
 | |
| 
 | |
| 	/* set default parameters and overrides */
 | |
| 	openmode = "w";
 | |
| 	Thisbinary = (!Rxascii) || Rxbinary;
 | |
| 	if (Lzmanag)
 | |
| 		zmanag = Lzmanag;
 | |
| 
 | |
| 	/*
 | |
| 	 *  Process ZMODEM remote file management requests
 | |
| 	 */
 | |
| 	if (!Rxbinary && zconv == ZCNL)	/* Remote ASCII override */
 | |
| 		Thisbinary = 0;
 | |
| 	if (zconv == ZCBIN)	/* Remote Binary override */
 | |
| 		Thisbinary = TRUE;
 | |
| 	else if (zmanag == ZMAPND)
 | |
| 		openmode = "a";
 | |
| 
 | |
| #ifndef BIX
 | |
| 	/* Check for existing file */
 | |
| 	if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
 | |
| 		fclose(fout);  return ERROR;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
 | |
| 
 | |
| 	p = name + 1 + strlen(name);
 | |
| 	if (*p) {	/* file coming from Unix or DOS system */
 | |
| 		sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
 | |
| #ifndef vax11c
 | |
| 		if (Filemode & UNIXFILE)
 | |
| 			++Thisbinary;
 | |
| #endif
 | |
| 		if (Verbose) {
 | |
| 			fprintf(stderr,  "\nIncoming: %s %ld %lo %o\n",
 | |
| 			  name, Bytesleft, Modtime, Filemode);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| #ifdef BIX
 | |
| 	if ((fout=fopen("scratchpad", openmode)) == NULL)
 | |
| 		return ERROR;
 | |
| 	return OK;
 | |
| #else
 | |
| 
 | |
| 	else {		/* File coming from CP/M system */
 | |
| 		for (p=name; *p; ++p)		/* change / to _ */
 | |
| 			if ( *p == '/')
 | |
| 				*p = '_';
 | |
| 
 | |
| 		if ( *--p == '.')		/* zap trailing period */
 | |
| 			*p = 0;
 | |
| 	}
 | |
| 
 | |
| #ifndef vax11c
 | |
| 	if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
 | |
| 	  && !(Filemode&UNIXFILE))
 | |
| 		uncaps(name);
 | |
| #endif
 | |
| 	if (Topipe > 0) {
 | |
| 		sprintf(Pathname, "%s %s", Progname+2, name);
 | |
| 		if (Verbose)
 | |
| 			fprintf(stderr,  "Topipe: %s %s\n",
 | |
| 			  Pathname, Thisbinary?"BIN":"ASCII");
 | |
| #ifndef vax11c
 | |
| 		if ((fout=popen(Pathname, "w")) == NULL)
 | |
| 			return ERROR;
 | |
| #endif
 | |
| 	} else {
 | |
| 		strcpy(Pathname, name);
 | |
| 		if (Verbose) {
 | |
| 			fprintf(stderr,  "Receiving %s %s %s\n",
 | |
| 			  name, Thisbinary?"BIN":"ASCII", openmode);
 | |
| 		}
 | |
| 		checkpath(name);
 | |
| 		if (Nflag)
 | |
| 			name = "/dev/null";
 | |
| #ifndef vax11c
 | |
| #ifdef OMEN
 | |
| 		if (name[0] == '!' || name[0] == '|') {
 | |
| 			if ( !(fout = popen(name+1, "w"))) {
 | |
| 				return ERROR;
 | |
| 			}
 | |
| 			Topipe = -1;  return(OK);
 | |
| 		}
 | |
| #endif
 | |
| #endif
 | |
| #ifdef MD
 | |
| 		fout = fopen(name, openmode);
 | |
| 		if ( !fout)
 | |
| 			if (make_dirs(name))
 | |
| 				fout = fopen(name, openmode);
 | |
| #else
 | |
| 		fout = fopen(name, openmode);
 | |
| #endif
 | |
| 		if ( !fout)
 | |
| 			return ERROR;
 | |
| 	}
 | |
| 	return OK;
 | |
| #endif /* BIX */
 | |
| }
 | |
| 
 | |
| #ifdef MD
 | |
| /*
 | |
|  *  Directory-creating routines from Public Domain TAR by John Gilmore
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * After a file/link/symlink/dir creation has failed, see if
 | |
|  * it's because some required directory was not present, and if
 | |
|  * so, create all required dirs.
 | |
|  */
 | |
| int make_dirs(pathname)
 | |
| register char *pathname;
 | |
| {
 | |
| 	register char *p;		/* Points into path */
 | |
| 	int madeone = 0;		/* Did we do anything yet? */
 | |
| 	int save_errno = errno;		/* Remember caller's errno */
 | |
| 	char *strchr();
 | |
| 
 | |
| 	if (errno != ENOENT)
 | |
| 		return 0;		/* Not our problem */
 | |
| 
 | |
| 	for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
 | |
| 		/* Avoid mkdir of empty string, if leading or double '/' */
 | |
| 		if (p == pathname || p[-1] == '/')
 | |
| 			continue;
 | |
| 		/* Avoid mkdir where last part of path is '.' */
 | |
| 		if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
 | |
| 			continue;
 | |
| 		*p = 0;				/* Truncate the path there */
 | |
| 		if ( !makedir(pathname, 0777)) {	/* Try to create it as a dir */
 | |
| 			vfile("Made directory %s\n", pathname);
 | |
| 			madeone++;		/* Remember if we made one */
 | |
| 			*p = '/';
 | |
| 			continue;
 | |
| 		}
 | |
| 		*p = '/';
 | |
| 		if (errno == EEXIST)		/* Directory already exists */
 | |
| 			continue;
 | |
| 		/*
 | |
| 		 * Some other error in the makedir.  We return to the caller.
 | |
| 		 */
 | |
| 		break;
 | |
| 	}
 | |
| 	errno = save_errno;		/* Restore caller's errno */
 | |
| 	return madeone;			/* Tell them to retry if we made one */
 | |
| }
 | |
| 
 | |
| #if (MD != 2)
 | |
| #define	TERM_SIGNAL(status)	((status) & 0x7F)
 | |
| #define TERM_COREDUMP(status)	(((status) & 0x80) != 0)
 | |
| #define TERM_VALUE(status)	((status) >> 8)
 | |
| /*
 | |
|  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
 | |
|  */
 | |
| int makedir(dpath, dmode)
 | |
| char *dpath;
 | |
| int dmode;
 | |
| {
 | |
| 	int cpid, status;
 | |
| 	struct stat statbuf;
 | |
| 
 | |
| 	if (stat(dpath,&statbuf) == 0) {
 | |
| 		errno = EEXIST;		/* Stat worked, so it already exists */
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	/* If stat fails for a reason other than non-existence, return error */
 | |
| 	if (errno != ENOENT) return -1; 
 | |
| 
 | |
| 	switch (cpid = fork()) {
 | |
| 
 | |
| 	case -1:			/* Error in fork() */
 | |
| 		return(-1);		/* Errno is set already */
 | |
| 
 | |
| 	case 0:				/* Child process */
 | |
| 		/*
 | |
| 		 * Cheap hack to set mode of new directory.  Since this
 | |
| 		 * child process is going away anyway, we zap its umask.
 | |
| 		 * FIXME, this won't suffice to set SUID, SGID, etc. on this
 | |
| 		 * directory.  Does anybody care?
 | |
| 		 */
 | |
| 		status = umask(0);	/* Get current umask */
 | |
| 		status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
 | |
| 		execl("/bin/mkdir", "mkdir", dpath, (char *)0);
 | |
| 		_exit(-1);		/* Can't exec /bin/mkdir */
 | |
| 	
 | |
| 	default:			/* Parent process */
 | |
| 		while (cpid != wait(&status)) ;	/* Wait for kid to finish */
 | |
| 	}
 | |
| 
 | |
| 	if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
 | |
| 		errno = EIO;		/* We don't know why, but */
 | |
| 		return -1;		/* /bin/mkdir failed */
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| #endif /* MD != 2 */
 | |
| #endif /* MD */
 | |
| 
 | |
| /*
 | |
|  * 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(buf, n)
 | |
| char *buf;
 | |
| register int n;
 | |
| {
 | |
| 	register char *p;
 | |
| 
 | |
| 	if (n == 0)
 | |
| 		return OK;
 | |
| 	if (Thisbinary) {
 | |
| 		for (p=buf; --n>=0; )
 | |
| 			putc( *p++, fout);
 | |
| 	}
 | |
| 	else {
 | |
| 		if (Eofseen)
 | |
| 			return OK;
 | |
| 		for (p=buf; --n>=0; ++p ) {
 | |
| 			if ( *p == '\r')
 | |
| 				continue;
 | |
| 			if (*p == CPMEOF) {
 | |
| 				Eofseen=TRUE; return OK;
 | |
| 			}
 | |
| 			putc(*p ,fout);
 | |
| 		}
 | |
| 	}
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| #ifndef vax11c
 | |
| /*
 | |
|  *  Send a character to modem.  Small is beautiful.
 | |
|  */
 | |
| void sendline(c)
 | |
| int c;
 | |
| {
 | |
| 	char d;
 | |
| 
 | |
| 	d = c;
 | |
| 	if (Verbose>6)
 | |
| 		fprintf(stderr, "Sendline: %x\n", c);
 | |
| 	write(1, &d, 1);
 | |
| }
 | |
| 
 | |
| void flushmo() {}
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /* make string s lower case */
 | |
| void uncaps(s)
 | |
| register char *s;
 | |
| {
 | |
| 	for ( ; *s; ++s)
 | |
| 		if (isupper(*s))
 | |
| 			*s = tolower(*s);
 | |
| }
 | |
| /*
 | |
|  * IsAnyLower returns TRUE if string s has lower case letters.
 | |
|  */
 | |
| int IsAnyLower(s)
 | |
| register char *s;
 | |
| {
 | |
| 	for ( ; *s; ++s)
 | |
| 		if (islower(*s))
 | |
| 			return TRUE;
 | |
| 	return FALSE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * 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 (char *)NULL;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Log an error
 | |
|  */
 | |
| /*VARARGS1*/
 | |
| void zperr(s,p,u)
 | |
| char *s, *p, *u;
 | |
| {
 | |
| 	if (Verbose <= 0)
 | |
| 		return;
 | |
| 	fprintf(stderr, "Retry %d: ", errors);
 | |
| 	fprintf(stderr, s, p, u);
 | |
| 	fprintf(stderr, "\n");
 | |
| }
 | |
| 
 | |
| /* send cancel string to get the other end to shut up */
 | |
| void canit()
 | |
| {
 | |
| 	static char canistr[] = {
 | |
| 	 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
 | |
| 	};
 | |
| 
 | |
| #ifdef vax11c
 | |
| 	raw_wbuf(strlen(canistr), canistr);
 | |
| 	purgeline();
 | |
| #else
 | |
| 	printf(canistr);
 | |
| 	Lleft=0;	/* Do read next time ... */
 | |
| 	fflush(stdout);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| void report(sct)
 | |
| int sct;
 | |
| {
 | |
| 	if (Verbose>1)
 | |
| 		fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
 | |
| }
 | |
| 
 | |
| #ifndef vax11c
 | |
| /*
 | |
|  * 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
 | |
|  */
 | |
| void chkinvok(s)
 | |
| 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]=='z')
 | |
| 		Batch = TRUE;
 | |
| 	if (s[0]=='r' && s[1]=='b')
 | |
| 		Batch = Nozmodem = TRUE;
 | |
| 	if (s[2] && s[0]=='r' && s[1]=='b')
 | |
| 		Topipe = 1;
 | |
| 	if (s[2] && s[0]=='r' && s[1]=='z')
 | |
| 		Topipe = 1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Totalitarian Communist pathname processing
 | |
|  */
 | |
| void checkpath(name)
 | |
| char *name;
 | |
| {
 | |
| 	if (Restricted) {
 | |
| 		if (fopen(name, "r") != NULL) {
 | |
| 			canit();
 | |
| 			fprintf(stderr, "\r\nrz: %s exists\n", name);
 | |
| 			bibi(-1);
 | |
| 		}
 | |
| 		/* restrict pathnames to current tree or uucppublic */
 | |
| 		if ( substr(name, "../")
 | |
| 		 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
 | |
| 			canit();
 | |
| 			fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
 | |
| 			bibi(-1);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * 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()
 | |
| {
 | |
| 	register c, n;
 | |
| 	register cmdzack1flg;
 | |
| 
 | |
| 	if (Nozmodem)		/* Check for "rb" program name */
 | |
| 		return 0;
 | |
| 
 | |
| 
 | |
| 	for (n=Zmodem?15:5; --n>=0; ) {
 | |
| 		/* Set buffer length (0) and capability flags */
 | |
| #ifdef SEGMENTS
 | |
| 		stohdr(SEGMENTS*1024L);
 | |
| #else
 | |
| 		stohdr(0L);
 | |
| #endif
 | |
| #ifdef CANBREAK
 | |
| 		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
 | |
| #else
 | |
| 		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
 | |
| #endif
 | |
| 		if (Zctlesc)
 | |
| 			Txhdr[ZF0] |= TESCCTL;
 | |
| 		zshhdr(tryzhdrtype, Txhdr);
 | |
| 		if (tryzhdrtype == ZSKIP)	/* Don't skip too far */
 | |
| 			tryzhdrtype = ZRINIT;	/* CAF 8-21-87 */
 | |
| 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];
 | |
| 			tryzhdrtype = ZRINIT;
 | |
| 			c = zrdata(secbuf, 1024);
 | |
| 			mode(3);
 | |
| 			if (c == GOTCRCW)
 | |
| 				return ZFILE;
 | |
| 			zshhdr(ZNAK, Txhdr);
 | |
| 			goto again;
 | |
| 		case ZSINIT:
 | |
| 			Zctlesc = TESCCTL & Rxhdr[ZF0];
 | |
| 			if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
 | |
| 				stohdr(1L);
 | |
| 				zshhdr(ZACK, Txhdr);
 | |
| 				goto again;
 | |
| 			}
 | |
| 			zshhdr(ZNAK, Txhdr);
 | |
| 			goto again;
 | |
| 		case ZFREECNT:
 | |
| 			stohdr(getfree());
 | |
| 			zshhdr(ZACK, Txhdr);
 | |
| 			goto again;
 | |
| 		case ZCOMMAND:
 | |
| #ifdef vax11c
 | |
| 			return ERROR;
 | |
| #else
 | |
| 			cmdzack1flg = Rxhdr[ZF0];
 | |
| 			if (zrdata(secbuf, 1024) == GOTCRCW) {
 | |
| 				if (cmdzack1flg & ZCACK1)
 | |
| 					stohdr(0L);
 | |
| 				else
 | |
| 					stohdr((long)sys2(secbuf));
 | |
| 				purgeline();	/* dump impatient questions */
 | |
| 				do {
 | |
| 					zshhdr(ZCOMPL, Txhdr);
 | |
| 				}
 | |
| 				while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
 | |
| 				ackbibi();
 | |
| 				if (cmdzack1flg & ZCACK1)
 | |
| 					exec2(secbuf);
 | |
| 				return ZCOMPL;
 | |
| 			}
 | |
| 			zshhdr(ZNAK, Txhdr); goto again;
 | |
| #endif
 | |
| 		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()
 | |
| {
 | |
| 	register 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()
 | |
| {
 | |
| 	register c, n;
 | |
| 	long rxbytes;
 | |
| 
 | |
| 	Eofseen=FALSE;
 | |
| 	if (procheader(secbuf) == ERROR) {
 | |
| 		return (tryzhdrtype = ZSKIP);
 | |
| 	}
 | |
| 
 | |
| 	n = 20; rxbytes = 0l;
 | |
| 
 | |
| 	for (;;) {
 | |
| #ifdef SEGMENTS
 | |
| 		chinseg = 0;
 | |
| #endif
 | |
| 		stohdr(rxbytes);
 | |
| 		zshhdr(ZRPOS, Txhdr);
 | |
| nxthdr:
 | |
| 		switch (c = zgethdr(Rxhdr, 0)) {
 | |
| 		default:
 | |
| 			vfile("rzfile: zgethdr returned %d", c);
 | |
| 			return ERROR;
 | |
| 		case ZNAK:
 | |
| 		case TIMEOUT:
 | |
| #ifdef SEGMENTS
 | |
| 			putsec(secbuf, chinseg);
 | |
| 			chinseg = 0;
 | |
| #endif
 | |
| 			if ( --n < 0) {
 | |
| 				vfile("rzfile: zgethdr returned %d", c);
 | |
| 				return ERROR;
 | |
| 			}
 | |
| 		case ZFILE:
 | |
| 			zrdata(secbuf, 1024);
 | |
| 			continue;
 | |
| 		case ZEOF:
 | |
| #ifdef SEGMENTS
 | |
| 			putsec(secbuf, chinseg);
 | |
| 			chinseg = 0;
 | |
| #endif
 | |
| 			if (rclhdr(Rxhdr) != rxbytes) {
 | |
| 				/*
 | |
| 				 * Ignore eof if it's at wrong place - force
 | |
| 				 *  a timeout because the eof might have gone
 | |
| 				 *  out before we sent our zrpos.
 | |
| 				 */
 | |
| 				errors = 0;  goto nxthdr;
 | |
| 			}
 | |
| 			if (closeit()) {
 | |
| 				tryzhdrtype = ZFERR;
 | |
| 				vfile("rzfile: closeit returned <> 0");
 | |
| 				return ERROR;
 | |
| 			}
 | |
| 			vfile("rzfile: normal EOF");
 | |
| 			return c;
 | |
| 		case ERROR:	/* Too much garbage in header search error */
 | |
| #ifdef SEGMENTS
 | |
| 			putsec(secbuf, chinseg);
 | |
| 			chinseg = 0;
 | |
| #endif
 | |
| 			if ( --n < 0) {
 | |
| 				vfile("rzfile: zgethdr returned %d", c);
 | |
| 				return ERROR;
 | |
| 			}
 | |
| 			zmputs(Attn);
 | |
| 			continue;
 | |
| 		case ZSKIP:
 | |
| #ifdef SEGMENTS
 | |
| 			putsec(secbuf, chinseg);
 | |
| 			chinseg = 0;
 | |
| #endif
 | |
| 			closeit();
 | |
| 			vfile("rzfile: Sender SKIPPED file");
 | |
| 			return c;
 | |
| 		case ZDATA:
 | |
| 			if (rclhdr(Rxhdr) != rxbytes) {
 | |
| 				if ( --n < 0) {
 | |
| 					return ERROR;
 | |
| 				}
 | |
| #ifdef SEGMENTS
 | |
| 				putsec(secbuf, chinseg);
 | |
| 				chinseg = 0;
 | |
| #endif
 | |
| 				zmputs(Attn);  continue;
 | |
| 			}
 | |
| moredata:
 | |
| 			if (Verbose>1)
 | |
| 				fprintf(stderr, "\r%7ld ZMODEM%s    ",
 | |
| 				  rxbytes, Crc32?" CRC-32":"");
 | |
| #ifdef SEGMENTS
 | |
| 			if (chinseg >= (1024 * SEGMENTS)) {
 | |
| 				putsec(secbuf, chinseg);
 | |
| 				chinseg = 0;
 | |
| 			}
 | |
| 			switch (c = zrdata(secbuf+chinseg, 1024))
 | |
| #else
 | |
| 			switch (c = zrdata(secbuf, 1024))
 | |
| #endif
 | |
| 			{
 | |
| 			case ZCAN:
 | |
| #ifdef SEGMENTS
 | |
| 				putsec(secbuf, chinseg);
 | |
| 				chinseg = 0;
 | |
| #endif
 | |
| 				vfile("rzfile: zgethdr returned %d", c);
 | |
| 				return ERROR;
 | |
| 			case ERROR:	/* CRC error */
 | |
| #ifdef SEGMENTS
 | |
| 				putsec(secbuf, chinseg);
 | |
| 				chinseg = 0;
 | |
| #endif
 | |
| 				if ( --n < 0) {
 | |
| 					vfile("rzfile: zgethdr returned %d", c);
 | |
| 					return ERROR;
 | |
| 				}
 | |
| 				zmputs(Attn);
 | |
| 				continue;
 | |
| 			case TIMEOUT:
 | |
| #ifdef SEGMENTS
 | |
| 				putsec(secbuf, chinseg);
 | |
| 				chinseg = 0;
 | |
| #endif
 | |
| 				if ( --n < 0) {
 | |
| 					vfile("rzfile: zgethdr returned %d", c);
 | |
| 					return ERROR;
 | |
| 				}
 | |
| 				continue;
 | |
| 			case GOTCRCW:
 | |
| 				n = 20;
 | |
| #ifdef SEGMENTS
 | |
| 				chinseg += Rxcount;
 | |
| 				putsec(secbuf, chinseg);
 | |
| 				chinseg = 0;
 | |
| #else
 | |
| 				putsec(secbuf, Rxcount);
 | |
| #endif
 | |
| 				rxbytes += Rxcount;
 | |
| 				stohdr(rxbytes);
 | |
| 				zshhdr(ZACK, Txhdr);
 | |
| 				sendline(XON);
 | |
| 				goto nxthdr;
 | |
| 			case GOTCRCQ:
 | |
| 				n = 20;
 | |
| #ifdef SEGMENTS
 | |
| 				chinseg += Rxcount;
 | |
| #else
 | |
| 				putsec(secbuf, Rxcount);
 | |
| #endif
 | |
| 				rxbytes += Rxcount;
 | |
| 				stohdr(rxbytes);
 | |
| 				zshhdr(ZACK, Txhdr);
 | |
| 				goto moredata;
 | |
| 			case GOTCRCG:
 | |
| 				n = 20;
 | |
| #ifdef SEGMENTS
 | |
| 				chinseg += Rxcount;
 | |
| #else
 | |
| 				putsec(secbuf, Rxcount);
 | |
| #endif
 | |
| 				rxbytes += Rxcount;
 | |
| 				goto moredata;
 | |
| 			case GOTCRCE:
 | |
| 				n = 20;
 | |
| #ifdef SEGMENTS
 | |
| 				chinseg += Rxcount;
 | |
| #else
 | |
| 				putsec(secbuf, Rxcount);
 | |
| #endif
 | |
| 				rxbytes += Rxcount;
 | |
| 				goto nxthdr;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Send a string to the modem, processing for \336 (sleep 1 sec)
 | |
|  *   and \335 (break signal)
 | |
|  */
 | |
| void zmputs(s)
 | |
| char *s;
 | |
| {
 | |
| 	register c;
 | |
| 
 | |
| 	while (*s) {
 | |
| 		switch (c = *s++) {
 | |
| 		case '\336':
 | |
| 			sleep(1); continue;
 | |
| 		case '\335':
 | |
| 			sendbrk(); continue;
 | |
| 		default:
 | |
| 			sendline(c);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Close the receive dataset, return OK or ERROR
 | |
|  */
 | |
| int closeit()
 | |
| {
 | |
| 	time_t q;
 | |
| 
 | |
| #ifndef vax11c
 | |
| 	if (Topipe) {
 | |
| 		if (pclose(fout)) {
 | |
| 			return ERROR;
 | |
| 		}
 | |
| 		return OK;
 | |
| 	}
 | |
| #endif
 | |
| 	if (fclose(fout)==ERROR) {
 | |
| 		fprintf(stderr, "file close ERROR\n");
 | |
| 		return ERROR;
 | |
| 	}
 | |
| #ifndef vax11c
 | |
| 	if (Modtime) {
 | |
| 		timep[0] = time(&q);
 | |
| 		timep[1] = Modtime;
 | |
| 		utime(Pathname, (struct utimbuf *) timep);
 | |
| 	}
 | |
| #endif
 | |
| 	if ((Filemode&S_IFMT) == S_IFREG)
 | |
| 		chmod(Pathname, (07777 & Filemode));
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Ack a ZFIN packet, let byegones be byegones
 | |
|  */
 | |
| void ackbibi()
 | |
| {
 | |
| 	register n;
 | |
| 
 | |
| 	vfile("ackbibi:");
 | |
| 	Readnum = 1;
 | |
| 	stohdr(0L);
 | |
| 	for (n=3; --n>=0; ) {
 | |
| 		purgeline();
 | |
| 		zshhdr(ZFIN, Txhdr);
 | |
| 		switch (readline(100)) {
 | |
| 		case 'O':
 | |
| 			readline(1);	/* Discard 2nd 'O' */
 | |
| 			vfile("ackbibi complete");
 | |
| 			return;
 | |
| 		case RCDO:
 | |
| 			return;
 | |
| 		case TIMEOUT:
 | |
| 		default:
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Local console output simulation
 | |
|  */
 | |
| void bttyout(c)
 | |
| int c;
 | |
| {
 | |
| 	if (Verbose || Fromcu)
 | |
| 		putc(c, stderr);
 | |
| }
 | |
| 
 | |
| #ifndef vax11c
 | |
| /*
 | |
|  * Strip leading ! if present, do shell escape. 
 | |
|  */
 | |
| int sys2(s)
 | |
| register char *s;
 | |
| {
 | |
| 	if (*s == '!')
 | |
| 		++s;
 | |
| 	return system(s);
 | |
| }
 | |
| /*
 | |
|  * Strip leading ! if present, do exec.
 | |
|  */
 | |
| void exec2(s)
 | |
| register char *s;
 | |
| {
 | |
| 	if (*s == '!')
 | |
| 		++s;
 | |
| 	mode(0);
 | |
| 	execl("/bin/sh", "sh", "-c", s);
 | |
| }
 | |
| #endif
 | |
| /* End of rz.c */
 | 
