xref: /minix3/minix/commands/zmodem/rz.c (revision d0055759dd8892194db7fce6acc5085d5c9aeaee)
1433d6423SLionel Sambuc #define VERSION "2.03 05-17-88"
2433d6423SLionel Sambuc #define PUBDIR "/usr/spool/uucppublic"
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc /*% cc -compat -M2 -Ox -K -i -DMD -DOMEN % -o rz; size rz;
5433d6423SLionel Sambuc <-xtx-*> cc386 -Ox -DMD -DOMEN -DSEGMENTS=8 rz.c -o $B/rz;  size $B/rz
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * rz.c By Chuck Forsberg
8433d6423SLionel Sambuc  *
9433d6423SLionel Sambuc  *	cc -O rz.c -o rz		USG (3.0) Unix
10433d6423SLionel Sambuc  * 	cc -O -DV7  rz.c -o rz		Unix V7, BSD 2.8 - 4.3
11433d6423SLionel Sambuc  *
12433d6423SLionel Sambuc  *	ln rz rb;  ln rz rx			For either system
13433d6423SLionel Sambuc  *
14433d6423SLionel Sambuc  *	ln rz /usr/bin/rzrmail		For remote mail.  Make this the
15433d6423SLionel Sambuc  *					login shell. rzrmail then calls
16433d6423SLionel Sambuc  *					rmail(1) to deliver mail.
17433d6423SLionel Sambuc  *
18433d6423SLionel Sambuc  * To compile on VMS:
19433d6423SLionel Sambuc  *
20433d6423SLionel Sambuc  *	define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
21433d6423SLionel Sambuc  *	cc rz.c
22433d6423SLionel Sambuc  *	cc vvmodem.c
23433d6423SLionel Sambuc  *	link rz,vvmodem
24433d6423SLionel Sambuc  *	rz :== $disk:[username.subdir]rz.exe
25433d6423SLionel Sambuc  *
26433d6423SLionel Sambuc  *
27433d6423SLionel Sambuc  *  Unix is a trademark of Western Electric Company
28433d6423SLionel Sambuc  *
29433d6423SLionel Sambuc  * A program for Unix to receive files and commands from computers running
30433d6423SLionel Sambuc  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
31433d6423SLionel Sambuc  *  rz uses Unix buffered input to reduce wasted CPU time.
32433d6423SLionel Sambuc  *
33433d6423SLionel Sambuc  * Iff the program is invoked by rzCOMMAND, output is piped to
34433d6423SLionel Sambuc  * "COMMAND filename"  (Unix only)
35433d6423SLionel Sambuc  *
36433d6423SLionel Sambuc  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
37433d6423SLionel Sambuc  *  read(2) the same way as Unix. ONEREAD must be defined to force one
38433d6423SLionel Sambuc  *  character reads for these systems. Added 7-01-84 CAF
39433d6423SLionel Sambuc  *
40433d6423SLionel Sambuc  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF
41433d6423SLionel Sambuc  *
42433d6423SLionel Sambuc  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
43433d6423SLionel Sambuc  *  Byte Information Exchange.
44433d6423SLionel Sambuc  *
45433d6423SLionel Sambuc  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
46433d6423SLionel Sambuc  *  doesn't work properly (even though it compiles without error!),
47433d6423SLionel Sambuc  *
48433d6423SLionel Sambuc  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
49433d6423SLionel Sambuc  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
50433d6423SLionel Sambuc  *
51433d6423SLionel Sambuc  *  VMS flavor hacks begin with rz version 2.00
52433d6423SLionel Sambuc  *
53433d6423SLionel Sambuc  *  -DMD may be added to compiler command line to compile in
54433d6423SLionel Sambuc  *    Directory-creating routines from Public Domain TAR by John Gilmore
55433d6423SLionel Sambuc  *
56433d6423SLionel Sambuc  *  HOWMANY may be tuned for best performance
57433d6423SLionel Sambuc  *
58433d6423SLionel Sambuc  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
59433d6423SLionel Sambuc  */
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc #include <sys/types.h>
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc #ifdef vax11c
64433d6423SLionel Sambuc #include <types.h>
65433d6423SLionel Sambuc #include <stat.h>
66433d6423SLionel Sambuc #define LOGFILE "rzlog.tmp"
67433d6423SLionel Sambuc #define OS "VMS"
68433d6423SLionel Sambuc #define BUFREAD
69433d6423SLionel Sambuc extern int errno;
70433d6423SLionel Sambuc #define SS_NORMAL SS$_NORMAL
71433d6423SLionel Sambuc #else
72433d6423SLionel Sambuc /* Not vax11c */
73433d6423SLionel Sambuc #define SS_NORMAL 0
74433d6423SLionel Sambuc #define LOGFILE "/tmp/rzlog"
75433d6423SLionel Sambuc #endif
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc #include <time.h>
78433d6423SLionel Sambuc #include <ctype.h>
79433d6423SLionel Sambuc #include <errno.h>
80433d6423SLionel Sambuc #include <signal.h>
81433d6423SLionel Sambuc #include <setjmp.h>
82433d6423SLionel Sambuc #include <string.h>
83433d6423SLionel Sambuc #include <stdlib.h>
84433d6423SLionel Sambuc #include <unistd.h>
85433d6423SLionel Sambuc #include <utime.h>
86433d6423SLionel Sambuc #include <stdio.h>
87433d6423SLionel Sambuc #include <stdarg.h>
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc #define OK 0
90433d6423SLionel Sambuc #define FALSE 0
91433d6423SLionel Sambuc #define TRUE 1
92433d6423SLionel Sambuc #undef ERROR
93433d6423SLionel Sambuc #define ERROR (-1)
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc long getfree(void);
97433d6423SLionel Sambuc void alrm(int sig );
98433d6423SLionel Sambuc int main(int argc , char *argv []);
99433d6423SLionel Sambuc int usage(void);
100433d6423SLionel Sambuc int wcreceive(int argc , char **argp );
101433d6423SLionel Sambuc int wcrxpn(char *rpn );
102433d6423SLionel Sambuc int wcrx(void);
103433d6423SLionel Sambuc int wcgetsec(char *rxbuf , int maxtime );
104433d6423SLionel Sambuc int readline(int timeout );
105433d6423SLionel Sambuc void purgeline(void);
106433d6423SLionel Sambuc int procheader(char *name );
107433d6423SLionel Sambuc int make_dirs(char *pathname );
108433d6423SLionel Sambuc int makedir(char *dpath , int dmode );
109433d6423SLionel Sambuc int putsec(char *buf , int n );
110433d6423SLionel Sambuc void sendline(int c );
111433d6423SLionel Sambuc void flushmo(void);
112433d6423SLionel Sambuc void uncaps(char *s );
113433d6423SLionel Sambuc int IsAnyLower(char *s );
114433d6423SLionel Sambuc char *substr(char *s , char *t );
115433d6423SLionel Sambuc void zperr();
116433d6423SLionel Sambuc void canit(void);
117433d6423SLionel Sambuc void report(int sct );
118433d6423SLionel Sambuc void chkinvok(char *s );
119433d6423SLionel Sambuc void checkpath(char *name );
120433d6423SLionel Sambuc int tryz(void);
121433d6423SLionel Sambuc int rzfiles(void);
122433d6423SLionel Sambuc int rzfile(void);
123433d6423SLionel Sambuc void zmputs(char *s );
124433d6423SLionel Sambuc int closeit(void);
125433d6423SLionel Sambuc void ackbibi(void);
126433d6423SLionel Sambuc void bttyout(int c );
127433d6423SLionel Sambuc int sys2(char *s );
128433d6423SLionel Sambuc void exec2(char *s );
129433d6423SLionel Sambuc /*
130433d6423SLionel Sambuc  *  Debugging information output interface routine
131433d6423SLionel Sambuc  */
132433d6423SLionel Sambuc void vfile(const char *s, ...);
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc /*
135433d6423SLionel Sambuc  * Max value for HOWMANY is 255.
136433d6423SLionel Sambuc  *   A larger value reduces system overhead but may evoke kernel bugs.
137433d6423SLionel Sambuc  *   133 corresponds to an XMODEM/CRC sector
138433d6423SLionel Sambuc  */
139433d6423SLionel Sambuc #ifndef HOWMANY
140433d6423SLionel Sambuc #define HOWMANY 133
141433d6423SLionel Sambuc #endif
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc /* Ward Christensen / CP/M parameters - Don't change these! */
144433d6423SLionel Sambuc #define ENQ 005
145433d6423SLionel Sambuc #define CAN ('X'&037)
146433d6423SLionel Sambuc #define XOFF ('s'&037)
147433d6423SLionel Sambuc #define XON ('q'&037)
148433d6423SLionel Sambuc #define SOH 1
149433d6423SLionel Sambuc #define STX 2
150433d6423SLionel Sambuc #define EOT 4
151433d6423SLionel Sambuc #define ACK 6
152433d6423SLionel Sambuc #define NAK 025
153433d6423SLionel Sambuc #define CPMEOF 032
154433d6423SLionel Sambuc #define WANTCRC 0103	/* send C not NAK to get crc not checksum */
155433d6423SLionel Sambuc #define TIMEOUT (-2)
156433d6423SLionel Sambuc #define RCDO (-3)
157433d6423SLionel Sambuc #define ERRORMAX 5
158433d6423SLionel Sambuc #define RETRYMAX 5
159433d6423SLionel Sambuc #define WCEOT (-10)
160433d6423SLionel Sambuc #define PATHLEN 257	/* ready for 4.2 bsd ? */
161433d6423SLionel Sambuc #define UNIXFILE 0xF000	/* The S_IFMT file mask bit for stat */
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc int Zmodem=0;		/* ZMODEM protocol requested */
164433d6423SLionel Sambuc int Nozmodem = 0;	/* If invoked as "rb" */
165433d6423SLionel Sambuc unsigned Baudrate = 2400;
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc #ifdef vax11c
168433d6423SLionel Sambuc #include "vrzsz.c"	/* most of the system dependent stuff here */
169433d6423SLionel Sambuc #else
170433d6423SLionel Sambuc #include "rbsb.c"	/* most of the system dependent stuff here */
171433d6423SLionel Sambuc #endif
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc #include "crctab.c"
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc FILE *fout;
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc /*
178433d6423SLionel Sambuc  * Routine to calculate the free bytes on the current file system
179433d6423SLionel Sambuc  *  ~0 means many free bytes (unknown)
180433d6423SLionel Sambuc  */
getfree()181433d6423SLionel Sambuc long getfree()
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc 	return(~0L);	/* many free bytes ... */
184433d6423SLionel Sambuc }
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc int Lastrx;
187433d6423SLionel Sambuc int Crcflg;
188433d6423SLionel Sambuc int Firstsec;
189433d6423SLionel Sambuc int Eofseen;		/* indicates cpm eof (^Z) has been received */
190433d6423SLionel Sambuc int errors;
191433d6423SLionel Sambuc int Restricted=0;	/* restricted; no /.. or ../ in filenames */
192433d6423SLionel Sambuc #ifdef ONEREAD
193433d6423SLionel Sambuc /* Sorry, Regulus and some others don't work right in raw mode! */
194433d6423SLionel Sambuc int Readnum = 1;	/* Number of bytes to ask for in read() from modem */
195433d6423SLionel Sambuc #else
196433d6423SLionel Sambuc int Readnum = HOWMANY;	/* Number of bytes to ask for in read() from modem */
197433d6423SLionel Sambuc #endif
198433d6423SLionel Sambuc 
199433d6423SLionel Sambuc #define DEFBYTL 2000000000L	/* default rx file size */
200433d6423SLionel Sambuc long Bytesleft;		/* number of bytes of incoming file left */
201433d6423SLionel Sambuc long Modtime;		/* Unix style mod time for incoming file */
202433d6423SLionel Sambuc int Filemode;		/* Unix style mode for incoming file */
203433d6423SLionel Sambuc char Pathname[PATHLEN];
204433d6423SLionel Sambuc char *Progname;		/* the name by which we were called */
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc int Batch=0;
207433d6423SLionel Sambuc int Topipe=0;
208433d6423SLionel Sambuc int MakeLCPathname=TRUE;	/* make received pathname lower case */
209433d6423SLionel Sambuc int Verbose=0;
210433d6423SLionel Sambuc int Quiet=0;		/* overrides logic that would otherwise set verbose */
211433d6423SLionel Sambuc int Nflag = 0;		/* Don't really transfer files */
212433d6423SLionel Sambuc int Rxclob=FALSE;	/* Clobber existing file */
213433d6423SLionel Sambuc int Rxbinary=FALSE;	/* receive all files in bin mode */
214433d6423SLionel Sambuc int Rxascii=FALSE;	/* receive files in ascii (translate) mode */
215433d6423SLionel Sambuc int Thisbinary;		/* current file is to be received in bin mode */
216433d6423SLionel Sambuc int Blklen;		/* record length of received packets */
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc #ifdef SEGMENTS
219433d6423SLionel Sambuc int chinseg = 0;	/* Number of characters received in this data seg */
220433d6423SLionel Sambuc char secbuf[1+(SEGMENTS+1)*1024];
221433d6423SLionel Sambuc #else
222433d6423SLionel Sambuc char secbuf[1025];
223433d6423SLionel Sambuc #endif
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc char linbuf[HOWMANY];
227433d6423SLionel Sambuc int Lleft=0;		/* number of characters in linbuf */
228433d6423SLionel Sambuc time_t timep[2];
229433d6423SLionel Sambuc char Lzmanag;		/* Local file management request */
230433d6423SLionel Sambuc char zconv;		/* ZMODEM file conversion request */
231433d6423SLionel Sambuc char zmanag;		/* ZMODEM file management request */
232433d6423SLionel Sambuc char ztrans;		/* ZMODEM file transport request */
233433d6423SLionel Sambuc int Zctlesc;		/* Encode control characters */
234433d6423SLionel Sambuc int Zrwindow = 1400;	/* RX window size (controls garbage count) */
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc jmp_buf tohere;		/* For the interrupt on RX timeout */
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc #define xsendline(c) sendline(c)
239433d6423SLionel Sambuc #include "zm.c"
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc int tryzhdrtype=ZRINIT;	/* Header type to send corresponding to Last rx close */
242433d6423SLionel Sambuc 
alrm(sig)243433d6423SLionel Sambuc void alrm(sig)
244433d6423SLionel Sambuc int sig;
245433d6423SLionel Sambuc {
246433d6423SLionel Sambuc 	longjmp(tohere, -1);
247433d6423SLionel Sambuc }
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc /* called by signal interrupt or terminate to clean things up */
bibi(int n)250433d6423SLionel Sambuc void bibi(int n)
251433d6423SLionel Sambuc {
252433d6423SLionel Sambuc 	if (Zmodem)
253433d6423SLionel Sambuc 		zmputs(Attn);
254433d6423SLionel Sambuc 	canit(); mode(0);
255433d6423SLionel Sambuc 	fprintf(stderr, "rz: caught signal %d; exiting\n", n);
256433d6423SLionel Sambuc 	cucheck();
257433d6423SLionel Sambuc 	exit(128+n);
258433d6423SLionel Sambuc }
259433d6423SLionel Sambuc 
main(int argc,char * argv[])260433d6423SLionel Sambuc int main(int argc, char *argv[])
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc 	register char *cp;
263433d6423SLionel Sambuc 	register int npats;
264433d6423SLionel Sambuc 	char *virgin, **patts;
265433d6423SLionel Sambuc 	int exitcode = 0;
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	Rxtimeout = 100;
268433d6423SLionel Sambuc 	setbuf(stderr, (char *)NULL);
269433d6423SLionel Sambuc 	if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
270433d6423SLionel Sambuc 		Restricted=TRUE;
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc 	from_cu();
273433d6423SLionel Sambuc #ifdef vax11c
274433d6423SLionel Sambuc 	Progname = virgin = "rz";
275433d6423SLionel Sambuc #else
276433d6423SLionel Sambuc 	chkinvok(virgin=argv[0]);	/* if called as [-]rzCOMMAND set flag */
277433d6423SLionel Sambuc #endif
278433d6423SLionel Sambuc 	npats = 0;
279433d6423SLionel Sambuc 	while (--argc) {
280433d6423SLionel Sambuc 		cp = *++argv;
281433d6423SLionel Sambuc 		if (*cp == '-') {
282433d6423SLionel Sambuc 			while( *++cp) {
283433d6423SLionel Sambuc 				switch(*cp) {
284433d6423SLionel Sambuc 				case '\\':
285433d6423SLionel Sambuc 					 cp[1] = toupper(cp[1]);  continue;
286433d6423SLionel Sambuc 				case '+':
287433d6423SLionel Sambuc 					Lzmanag = ZMAPND; break;
288433d6423SLionel Sambuc 				case 'a':
289433d6423SLionel Sambuc 					Rxascii=TRUE;  break;
290433d6423SLionel Sambuc 				case 'b':
291433d6423SLionel Sambuc 					Rxbinary=TRUE; break;
292433d6423SLionel Sambuc 				case 'c':
293433d6423SLionel Sambuc 					Crcflg=TRUE; break;
294433d6423SLionel Sambuc #ifndef vax11c
295433d6423SLionel Sambuc 				case 'D':
296433d6423SLionel Sambuc 					Nflag = TRUE; break;
297433d6423SLionel Sambuc #endif
298433d6423SLionel Sambuc 				case 'e':
299433d6423SLionel Sambuc 					Zctlesc = 1; break;
300433d6423SLionel Sambuc 				case 'p':
301433d6423SLionel Sambuc 					Lzmanag = ZMPROT;  break;
302433d6423SLionel Sambuc 				case 'q':
303433d6423SLionel Sambuc 					Quiet=TRUE; Verbose=0; break;
304433d6423SLionel Sambuc 				case 't':
305433d6423SLionel Sambuc 					if (--argc < 1) {
306433d6423SLionel Sambuc 						usage();
307433d6423SLionel Sambuc 					}
308433d6423SLionel Sambuc 					Rxtimeout = atoi(*++argv);
309433d6423SLionel Sambuc 					if (Rxtimeout<10 || Rxtimeout>1000)
310433d6423SLionel Sambuc 						usage();
311433d6423SLionel Sambuc 					break;
312433d6423SLionel Sambuc 				case 'w':
313433d6423SLionel Sambuc 					if (--argc < 1) {
314433d6423SLionel Sambuc 						usage();
315433d6423SLionel Sambuc 					}
316433d6423SLionel Sambuc 					Zrwindow = atoi(*++argv);
317433d6423SLionel Sambuc 					break;
318433d6423SLionel Sambuc 				case 'u':
319433d6423SLionel Sambuc 					MakeLCPathname=FALSE; break;
320433d6423SLionel Sambuc 				case 'v':
321433d6423SLionel Sambuc 					++Verbose; break;
322433d6423SLionel Sambuc 				case 'y':
323433d6423SLionel Sambuc 					Rxclob=TRUE; break;
324433d6423SLionel Sambuc 				default:
325433d6423SLionel Sambuc 					usage();
326433d6423SLionel Sambuc 				}
327433d6423SLionel Sambuc 			}
328433d6423SLionel Sambuc 		}
329433d6423SLionel Sambuc 		else if ( !npats && argc>0) {
330433d6423SLionel Sambuc 			if (argv[0][0]) {
331433d6423SLionel Sambuc 				npats=argc;
332433d6423SLionel Sambuc 				patts=argv;
333433d6423SLionel Sambuc 			}
334433d6423SLionel Sambuc 		}
335433d6423SLionel Sambuc 	}
336433d6423SLionel Sambuc 	if (npats > 1)
337433d6423SLionel Sambuc 		usage();
338433d6423SLionel Sambuc 	if (Batch && npats)
339433d6423SLionel Sambuc 		usage();
340433d6423SLionel Sambuc 	if (Verbose) {
341433d6423SLionel Sambuc 		if (freopen(LOGFILE, "a", stderr)==NULL) {
342433d6423SLionel Sambuc 			printf("Can't open log file %s\n",LOGFILE);
343433d6423SLionel Sambuc 			exit(0200);
344433d6423SLionel Sambuc 		}
345433d6423SLionel Sambuc 		setbuf(stderr, (char *)NULL);
346433d6423SLionel Sambuc 		fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
347433d6423SLionel Sambuc 	}
348433d6423SLionel Sambuc 	if (Fromcu && !Quiet) {
349433d6423SLionel Sambuc 		if (Verbose == 0)
350433d6423SLionel Sambuc 			Verbose = 2;
351433d6423SLionel Sambuc 	}
352433d6423SLionel Sambuc 	vfile("%s %s for %s\n", Progname, VERSION, OS);
353433d6423SLionel Sambuc 	mode(1);
354433d6423SLionel Sambuc 	if (signal(SIGINT, bibi) == SIG_IGN) {
355433d6423SLionel Sambuc 		signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
356433d6423SLionel Sambuc 	}
357433d6423SLionel Sambuc 	else {
358433d6423SLionel Sambuc 		signal(SIGINT, bibi); signal(SIGKILL, bibi);
359433d6423SLionel Sambuc 	}
360433d6423SLionel Sambuc 	signal(SIGTERM, bibi);
361433d6423SLionel Sambuc 	if (wcreceive(npats, patts)==ERROR) {
362433d6423SLionel Sambuc 		exitcode=0200;
363433d6423SLionel Sambuc 		canit();
364433d6423SLionel Sambuc 	}
365433d6423SLionel Sambuc 	mode(0);
366433d6423SLionel Sambuc 	vfile("exitcode = %d\n",exitcode);
367433d6423SLionel Sambuc 	if (exitcode && !Zmodem)	/* bellow again with all thy might. */
368433d6423SLionel Sambuc 		canit();
369433d6423SLionel Sambuc 	if (exitcode)
370433d6423SLionel Sambuc 		cucheck();
371433d6423SLionel Sambuc 	if (Verbose) putc('\n', stderr);
372433d6423SLionel Sambuc 	exit(exitcode ? exitcode:SS_NORMAL);
373433d6423SLionel Sambuc }
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc 
usage()376433d6423SLionel Sambuc int usage()
377433d6423SLionel Sambuc {
378433d6423SLionel Sambuc 	cucheck();
379433d6423SLionel Sambuc #ifdef vax11c
380433d6423SLionel Sambuc 	fprintf(stderr,"Usage:	rz [-abeuvy]\n");
381433d6423SLionel Sambuc #else
382433d6423SLionel Sambuc 	fprintf(stderr,"Usage:	rz [-abeuvy]		(ZMODEM)\n");
383433d6423SLionel Sambuc 	fprintf(stderr,"or	rb [-abuvy]		(YMODEM)\n");
384433d6423SLionel Sambuc 	fprintf(stderr,"or	rx [-abcv] file	(XMODEM or XMODEM-1k)\n");
385433d6423SLionel Sambuc #endif
386433d6423SLionel Sambuc 	fprintf(stderr,"	  -a ASCII transfer (strip CR)\n");
387433d6423SLionel Sambuc 	fprintf(stderr,"	  -b Binary transfer for all files\n");
388433d6423SLionel Sambuc #ifndef vax11c
389433d6423SLionel Sambuc 	fprintf(stderr,"	  -c Use 16 bit CRC	(XMODEM)\n");
390433d6423SLionel Sambuc #endif
391433d6423SLionel Sambuc 	fprintf(stderr,"	  -e Escape control characters	(ZMODEM)\n");
392433d6423SLionel Sambuc 	fprintf(stderr,"	  -v Verbose more v's give more info\n");
393433d6423SLionel Sambuc 	fprintf(stderr,"	  -y Yes, clobber existing file if any\n");
394433d6423SLionel Sambuc 	fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
395433d6423SLionel Sambuc 	  Progname, VERSION, OS);
396433d6423SLionel Sambuc 	fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
397433d6423SLionel Sambuc 	exit(SS_NORMAL);
398433d6423SLionel Sambuc }
399433d6423SLionel Sambuc 
vfile(const char * string,...)400433d6423SLionel Sambuc void vfile(const char *string, ...)
401433d6423SLionel Sambuc {
402433d6423SLionel Sambuc 	if (Verbose > 2) {
403433d6423SLionel Sambuc 		va_list args;
404433d6423SLionel Sambuc 		va_start(args, string);
405433d6423SLionel Sambuc 		vfprintf(stderr, string, args);
406433d6423SLionel Sambuc 		va_end(args);
407433d6423SLionel Sambuc 		fprintf(stderr, "\n");
408433d6423SLionel Sambuc 	}
409433d6423SLionel Sambuc }
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc /*
412433d6423SLionel Sambuc  * Let's receive something already.
413433d6423SLionel Sambuc  */
414433d6423SLionel Sambuc 
415433d6423SLionel Sambuc char *rbmsg =
416433d6423SLionel Sambuc "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
417433d6423SLionel Sambuc 
wcreceive(int argc,char ** argp)418433d6423SLionel Sambuc int wcreceive(int argc, char **argp)
419433d6423SLionel Sambuc {
420433d6423SLionel Sambuc 	register int c;
421433d6423SLionel Sambuc 
422433d6423SLionel Sambuc 	if (Batch || argc==0) {
423433d6423SLionel Sambuc 		Crcflg=1;
424433d6423SLionel Sambuc 		if ( !Quiet)
425433d6423SLionel Sambuc 			fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
426433d6423SLionel Sambuc 		if ((c=tryz())) {
427433d6423SLionel Sambuc 			if (c == ZCOMPL)
428433d6423SLionel Sambuc 				return OK;
429433d6423SLionel Sambuc 			if (c == ERROR)
430433d6423SLionel Sambuc 				goto fubar;
431433d6423SLionel Sambuc 			c = rzfiles();
432433d6423SLionel Sambuc 			if (c)
433433d6423SLionel Sambuc 				goto fubar;
434433d6423SLionel Sambuc 		} else {
435433d6423SLionel Sambuc 			for (;;) {
436433d6423SLionel Sambuc 				if (wcrxpn(secbuf)== ERROR)
437433d6423SLionel Sambuc 					goto fubar;
438433d6423SLionel Sambuc 				if (secbuf[0]==0)
439433d6423SLionel Sambuc 					return OK;
440433d6423SLionel Sambuc 				if (procheader(secbuf) == ERROR)
441433d6423SLionel Sambuc 					goto fubar;
442433d6423SLionel Sambuc 				if (wcrx()==ERROR)
443433d6423SLionel Sambuc 					goto fubar;
444433d6423SLionel Sambuc 			}
445433d6423SLionel Sambuc 		}
446433d6423SLionel Sambuc 	} else {
447433d6423SLionel Sambuc 		Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
448433d6423SLionel Sambuc 
449433d6423SLionel Sambuc 		procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
450433d6423SLionel Sambuc 		fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
451433d6423SLionel Sambuc 		if ((fout=fopen(Pathname, "w")) == NULL)
452433d6423SLionel Sambuc 			return ERROR;
453433d6423SLionel Sambuc 		if (wcrx()==ERROR)
454433d6423SLionel Sambuc 			goto fubar;
455433d6423SLionel Sambuc 	}
456433d6423SLionel Sambuc 	return OK;
457433d6423SLionel Sambuc fubar:
458433d6423SLionel Sambuc 	canit();
459433d6423SLionel Sambuc #ifndef vax11c
460433d6423SLionel Sambuc 	if (Topipe && fout) {
461433d6423SLionel Sambuc 		pclose(fout);  return ERROR;
462433d6423SLionel Sambuc 	}
463433d6423SLionel Sambuc #endif
464433d6423SLionel Sambuc 	if (fout)
465433d6423SLionel Sambuc 		fclose(fout);
466433d6423SLionel Sambuc #ifndef vax11c
467433d6423SLionel Sambuc 	if (Restricted) {
468433d6423SLionel Sambuc 		unlink(Pathname);
469433d6423SLionel Sambuc 		fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
470433d6423SLionel Sambuc 	}
471433d6423SLionel Sambuc #endif
472433d6423SLionel Sambuc 	return ERROR;
473433d6423SLionel Sambuc }
474433d6423SLionel Sambuc 
475433d6423SLionel Sambuc 
476433d6423SLionel Sambuc /*
477433d6423SLionel Sambuc  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
478433d6423SLionel Sambuc  * Length is indeterminate as long as less than Blklen
479433d6423SLionel Sambuc  * A null string represents no more files (YMODEM)
480433d6423SLionel Sambuc  *
481433d6423SLionel Sambuc  * Parameter rpn is for receiving a pathname
482433d6423SLionel Sambuc  */
wcrxpn(char * rpn)483433d6423SLionel Sambuc int wcrxpn(char *rpn)
484433d6423SLionel Sambuc {
485433d6423SLionel Sambuc 	register int c;
486433d6423SLionel Sambuc 
487433d6423SLionel Sambuc #ifdef NFGVMIN
488433d6423SLionel Sambuc 	readline(1);
489433d6423SLionel Sambuc #else
490433d6423SLionel Sambuc 	purgeline();
491433d6423SLionel Sambuc #endif
492433d6423SLionel Sambuc 
493433d6423SLionel Sambuc et_tu:
494433d6423SLionel Sambuc 	Firstsec=TRUE;  Eofseen=FALSE;
495433d6423SLionel Sambuc 	sendline(Crcflg?WANTCRC:NAK);
496433d6423SLionel Sambuc 	Lleft=0;	/* Do read next time ... */
497433d6423SLionel Sambuc 	while ((c = wcgetsec(rpn, 100)) != 0) {
498433d6423SLionel Sambuc 		if (c == WCEOT) {
499433d6423SLionel Sambuc 			zperr( "Pathname fetch returned %d", c);
500433d6423SLionel Sambuc 			sendline(ACK);
501433d6423SLionel Sambuc 			Lleft=0;	/* Do read next time ... */
502433d6423SLionel Sambuc 			readline(1);
503433d6423SLionel Sambuc 			goto et_tu;
504433d6423SLionel Sambuc 		}
505433d6423SLionel Sambuc 		return ERROR;
506433d6423SLionel Sambuc 	}
507433d6423SLionel Sambuc 	sendline(ACK);
508433d6423SLionel Sambuc 	return OK;
509433d6423SLionel Sambuc }
510433d6423SLionel Sambuc 
511433d6423SLionel Sambuc /*
512433d6423SLionel Sambuc  * Adapted from CMODEM13.C, written by
513433d6423SLionel Sambuc  * Jack M. Wierda and Roderick W. Hart
514433d6423SLionel Sambuc  */
515433d6423SLionel Sambuc 
wcrx()516433d6423SLionel Sambuc int wcrx()
517433d6423SLionel Sambuc {
518433d6423SLionel Sambuc 	register int sectnum, sectcurr;
519433d6423SLionel Sambuc 	register char sendchar;
520433d6423SLionel Sambuc 	int cblklen;			/* bytes to dump this block */
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc 	Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
523433d6423SLionel Sambuc 	sendchar=Crcflg?WANTCRC:NAK;
524433d6423SLionel Sambuc 
525433d6423SLionel Sambuc 	for (;;) {
526433d6423SLionel Sambuc 		sendline(sendchar);	/* send it now, we're ready! */
527433d6423SLionel Sambuc 		Lleft=0;	/* Do read next time ... */
528433d6423SLionel Sambuc 		sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
529433d6423SLionel Sambuc 		report(sectcurr);
530433d6423SLionel Sambuc 		if (sectcurr==((sectnum+1) &0377)) {
531433d6423SLionel Sambuc 			sectnum++;
532433d6423SLionel Sambuc 			cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
533433d6423SLionel Sambuc 			if (putsec(secbuf, cblklen)==ERROR)
534433d6423SLionel Sambuc 				return ERROR;
535433d6423SLionel Sambuc 			if ((Bytesleft-=cblklen) < 0)
536433d6423SLionel Sambuc 				Bytesleft = 0;
537433d6423SLionel Sambuc 			sendchar=ACK;
538433d6423SLionel Sambuc 		}
539433d6423SLionel Sambuc 		else if (sectcurr==(sectnum&0377)) {
540433d6423SLionel Sambuc 			zperr( "Received dup Sector");
541433d6423SLionel Sambuc 			sendchar=ACK;
542433d6423SLionel Sambuc 		}
543433d6423SLionel Sambuc 		else if (sectcurr==WCEOT) {
544433d6423SLionel Sambuc 			if (closeit())
545433d6423SLionel Sambuc 				return ERROR;
546433d6423SLionel Sambuc 			sendline(ACK);
547433d6423SLionel Sambuc 			Lleft=0;	/* Do read next time ... */
548433d6423SLionel Sambuc 			return OK;
549433d6423SLionel Sambuc 		}
550433d6423SLionel Sambuc 		else if (sectcurr==ERROR)
551433d6423SLionel Sambuc 			return ERROR;
552433d6423SLionel Sambuc 		else {
553433d6423SLionel Sambuc 			zperr( "Sync Error");
554433d6423SLionel Sambuc 			return ERROR;
555433d6423SLionel Sambuc 		}
556433d6423SLionel Sambuc 	}
557433d6423SLionel Sambuc }
558433d6423SLionel Sambuc 
559433d6423SLionel Sambuc /*
560433d6423SLionel Sambuc  * Wcgetsec fetches a Ward Christensen type sector.
561433d6423SLionel Sambuc  * Returns sector number encountered or ERROR if valid sector not received,
562433d6423SLionel Sambuc  * or CAN CAN received
563433d6423SLionel Sambuc  * or WCEOT if eot sector
564433d6423SLionel Sambuc  * time is timeout for first char, set to 4 seconds thereafter
565433d6423SLionel Sambuc  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
566433d6423SLionel Sambuc  *    (Caller must do that when he is good and ready to get next sector)
567433d6423SLionel Sambuc  */
568433d6423SLionel Sambuc 
wcgetsec(char * rxbuf,int maxtime)569433d6423SLionel Sambuc int wcgetsec(char *rxbuf, int maxtime)
570433d6423SLionel Sambuc {
571433d6423SLionel Sambuc 	register int checksum, wcj, firstch;
572433d6423SLionel Sambuc 	register unsigned short oldcrc;
573433d6423SLionel Sambuc 	register char *p;
574433d6423SLionel Sambuc 	int sectcurr;
575433d6423SLionel Sambuc 
576433d6423SLionel Sambuc 	for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
577433d6423SLionel Sambuc 
578433d6423SLionel Sambuc 		if ((firstch=readline(maxtime))==STX) {
579433d6423SLionel Sambuc 			Blklen=1024; goto get2;
580433d6423SLionel Sambuc 		}
581433d6423SLionel Sambuc 		if (firstch==SOH) {
582433d6423SLionel Sambuc 			Blklen=128;
583433d6423SLionel Sambuc get2:
584433d6423SLionel Sambuc 			sectcurr=readline(1);
585433d6423SLionel Sambuc 			if ((sectcurr+(oldcrc=readline(1)))==0377) {
586433d6423SLionel Sambuc 				oldcrc=checksum=0;
587433d6423SLionel Sambuc 				for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
588433d6423SLionel Sambuc 					if ((firstch=readline(1)) < 0)
589433d6423SLionel Sambuc 						goto bilge;
590433d6423SLionel Sambuc 					oldcrc=updcrc(firstch, oldcrc);
591433d6423SLionel Sambuc 					checksum += (*p++ = firstch);
592433d6423SLionel Sambuc 				}
593433d6423SLionel Sambuc 				if ((firstch=readline(1)) < 0)
594433d6423SLionel Sambuc 					goto bilge;
595433d6423SLionel Sambuc 				if (Crcflg) {
596433d6423SLionel Sambuc 					oldcrc=updcrc(firstch, oldcrc);
597433d6423SLionel Sambuc 					if ((firstch=readline(1)) < 0)
598433d6423SLionel Sambuc 						goto bilge;
599433d6423SLionel Sambuc 					oldcrc=updcrc(firstch, oldcrc);
600433d6423SLionel Sambuc 					if (oldcrc & 0xFFFF)
601433d6423SLionel Sambuc 						zperr( "CRC");
602433d6423SLionel Sambuc 					else {
603433d6423SLionel Sambuc 						Firstsec=FALSE;
604433d6423SLionel Sambuc 						return sectcurr;
605433d6423SLionel Sambuc 					}
606433d6423SLionel Sambuc 				}
607433d6423SLionel Sambuc 				else if (((checksum-firstch)&0377)==0) {
608433d6423SLionel Sambuc 					Firstsec=FALSE;
609433d6423SLionel Sambuc 					return sectcurr;
610433d6423SLionel Sambuc 				}
611433d6423SLionel Sambuc 				else
612433d6423SLionel Sambuc 					zperr( "Checksum");
613433d6423SLionel Sambuc 			}
614433d6423SLionel Sambuc 			else
615433d6423SLionel Sambuc 				zperr("Sector number garbled");
616433d6423SLionel Sambuc 		}
617433d6423SLionel Sambuc 		/* make sure eot really is eot and not just mixmash */
618433d6423SLionel Sambuc #ifdef NFGVMIN
619433d6423SLionel Sambuc 		else if (firstch==EOT && readline(1)==TIMEOUT)
620433d6423SLionel Sambuc 			return WCEOT;
621433d6423SLionel Sambuc #else
622433d6423SLionel Sambuc 		else if (firstch==EOT && Lleft==0)
623433d6423SLionel Sambuc 			return WCEOT;
624433d6423SLionel Sambuc #endif
625433d6423SLionel Sambuc 		else if (firstch==CAN) {
626433d6423SLionel Sambuc 			if (Lastrx==CAN) {
627433d6423SLionel Sambuc 				zperr( "Sender CANcelled");
628433d6423SLionel Sambuc 				return ERROR;
629433d6423SLionel Sambuc 			} else {
630433d6423SLionel Sambuc 				Lastrx=CAN;
631433d6423SLionel Sambuc 				continue;
632433d6423SLionel Sambuc 			}
633433d6423SLionel Sambuc 		}
634433d6423SLionel Sambuc 		else if (firstch==TIMEOUT) {
635433d6423SLionel Sambuc 			if (Firstsec)
636433d6423SLionel Sambuc 				goto humbug;
637433d6423SLionel Sambuc bilge:
638433d6423SLionel Sambuc 			zperr( "TIMEOUT");
639433d6423SLionel Sambuc 		}
640433d6423SLionel Sambuc 		else
641433d6423SLionel Sambuc 			zperr( "Got 0%o sector header", firstch);
642433d6423SLionel Sambuc 
643433d6423SLionel Sambuc humbug:
644433d6423SLionel Sambuc 		Lastrx=0;
645433d6423SLionel Sambuc 		while(readline(1)!=TIMEOUT)
646433d6423SLionel Sambuc 			;
647433d6423SLionel Sambuc 		if (Firstsec) {
648433d6423SLionel Sambuc 			sendline(Crcflg?WANTCRC:NAK);
649433d6423SLionel Sambuc 			Lleft=0;	/* Do read next time ... */
650433d6423SLionel Sambuc 		} else {
651433d6423SLionel Sambuc 			maxtime=40; sendline(NAK);
652433d6423SLionel Sambuc 			Lleft=0;	/* Do read next time ... */
653433d6423SLionel Sambuc 		}
654433d6423SLionel Sambuc 	}
655433d6423SLionel Sambuc 	/* try to stop the bubble machine. */
656433d6423SLionel Sambuc 	canit();
657433d6423SLionel Sambuc 	return ERROR;
658433d6423SLionel Sambuc }
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc #ifndef vax11c
661433d6423SLionel Sambuc /*
662433d6423SLionel Sambuc  * This version of readline is reasoably well suited for
663433d6423SLionel Sambuc  * reading many characters.
664433d6423SLionel Sambuc  *  (except, currently, for the Regulus version!)
665433d6423SLionel Sambuc  *
666433d6423SLionel Sambuc  * timeout is in tenths of seconds
667433d6423SLionel Sambuc  */
readline(int timeout)668433d6423SLionel Sambuc int readline(int timeout)
669433d6423SLionel Sambuc {
670433d6423SLionel Sambuc 	register int n;
671433d6423SLionel Sambuc 	static char *cdq;	/* pointer for removing chars from linbuf */
672433d6423SLionel Sambuc 
673433d6423SLionel Sambuc 	if (--Lleft >= 0) {
674433d6423SLionel Sambuc 		if (Verbose > 8) {
675433d6423SLionel Sambuc 			fprintf(stderr, "%02x ", *cdq&0377);
676433d6423SLionel Sambuc 		}
677433d6423SLionel Sambuc 		return (*cdq++ & 0377);
678433d6423SLionel Sambuc 	}
679433d6423SLionel Sambuc 	n = timeout/10;
680433d6423SLionel Sambuc 	if (n < 2)
681433d6423SLionel Sambuc 		n = 3;
682433d6423SLionel Sambuc 	if (Verbose > 5)
683433d6423SLionel Sambuc 		fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
684433d6423SLionel Sambuc 		  n, Readnum);
685433d6423SLionel Sambuc 	if (setjmp(tohere)) {
686433d6423SLionel Sambuc #ifdef TIOCFLUSH
687433d6423SLionel Sambuc /*		ioctl(iofd, TIOCFLUSH, 0); */
688433d6423SLionel Sambuc #endif
689433d6423SLionel Sambuc 		Lleft = 0;
690433d6423SLionel Sambuc 		if (Verbose>1)
691433d6423SLionel Sambuc 			fprintf(stderr, "Readline:TIMEOUT\n");
692433d6423SLionel Sambuc 		return TIMEOUT;
693433d6423SLionel Sambuc 	}
694433d6423SLionel Sambuc 	signal(SIGALRM, alrm); alarm(n);
695433d6423SLionel Sambuc 	Lleft=read(iofd, cdq=linbuf, Readnum);
696433d6423SLionel Sambuc 	alarm(0);
697433d6423SLionel Sambuc 	if (Verbose > 5) {
698433d6423SLionel Sambuc 		fprintf(stderr, "Read returned %d bytes\n", Lleft);
699433d6423SLionel Sambuc 	}
700433d6423SLionel Sambuc 	if (Lleft < 1)
701433d6423SLionel Sambuc 		return TIMEOUT;
702433d6423SLionel Sambuc 	--Lleft;
703433d6423SLionel Sambuc 	if (Verbose > 8) {
704433d6423SLionel Sambuc 		fprintf(stderr, "%02x ", *cdq&0377);
705433d6423SLionel Sambuc 	}
706433d6423SLionel Sambuc 	return (*cdq++ & 0377);
707433d6423SLionel Sambuc }
708433d6423SLionel Sambuc 
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc /*
712433d6423SLionel Sambuc  * Purge the modem input queue of all characters
713433d6423SLionel Sambuc  */
purgeline()714433d6423SLionel Sambuc void purgeline()
715433d6423SLionel Sambuc {
716433d6423SLionel Sambuc 	Lleft = 0;
717433d6423SLionel Sambuc #ifdef USG
718433d6423SLionel Sambuc 	ioctl(iofd, TCFLSH, 0);
719433d6423SLionel Sambuc #else
720433d6423SLionel Sambuc 	lseek(iofd, 0L, 2);
721433d6423SLionel Sambuc #endif
722433d6423SLionel Sambuc }
723433d6423SLionel Sambuc #endif
724433d6423SLionel Sambuc 
725433d6423SLionel Sambuc 
726433d6423SLionel Sambuc /*
727433d6423SLionel Sambuc  * Process incoming file information header
728433d6423SLionel Sambuc  */
procheader(char * name)729433d6423SLionel Sambuc int procheader(char *name)
730433d6423SLionel Sambuc {
731433d6423SLionel Sambuc 	register char *openmode, *p;
732433d6423SLionel Sambuc 
733433d6423SLionel Sambuc 	/* set default parameters and overrides */
734433d6423SLionel Sambuc 	openmode = "w";
735433d6423SLionel Sambuc 	Thisbinary = (!Rxascii) || Rxbinary;
736433d6423SLionel Sambuc 	if (Lzmanag)
737433d6423SLionel Sambuc 		zmanag = Lzmanag;
738433d6423SLionel Sambuc 
739433d6423SLionel Sambuc 	/*
740433d6423SLionel Sambuc 	 *  Process ZMODEM remote file management requests
741433d6423SLionel Sambuc 	 */
742433d6423SLionel Sambuc 	if (!Rxbinary && zconv == ZCNL)	/* Remote ASCII override */
743433d6423SLionel Sambuc 		Thisbinary = 0;
744433d6423SLionel Sambuc 	if (zconv == ZCBIN)	/* Remote Binary override */
745433d6423SLionel Sambuc 		Thisbinary = TRUE;
746433d6423SLionel Sambuc 	else if (zmanag == ZMAPND)
747433d6423SLionel Sambuc 		openmode = "a";
748433d6423SLionel Sambuc 
749433d6423SLionel Sambuc #ifndef BIX
750433d6423SLionel Sambuc 	/* Check for existing file */
751433d6423SLionel Sambuc 	if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
752433d6423SLionel Sambuc 		fclose(fout);  return ERROR;
753433d6423SLionel Sambuc 	}
754433d6423SLionel Sambuc #endif
755433d6423SLionel Sambuc 
756433d6423SLionel Sambuc 	Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
757433d6423SLionel Sambuc 
758433d6423SLionel Sambuc 	p = name + 1 + strlen(name);
759433d6423SLionel Sambuc 	if (*p) {	/* file coming from Unix or DOS system */
760433d6423SLionel Sambuc 		sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
761433d6423SLionel Sambuc #ifndef vax11c
762433d6423SLionel Sambuc 		if (Filemode & UNIXFILE)
763433d6423SLionel Sambuc 			++Thisbinary;
764433d6423SLionel Sambuc #endif
765433d6423SLionel Sambuc 		if (Verbose) {
766433d6423SLionel Sambuc 			fprintf(stderr,  "\nIncoming: %s %ld %lo %o\n",
767433d6423SLionel Sambuc 			  name, Bytesleft, Modtime, Filemode);
768433d6423SLionel Sambuc 		}
769433d6423SLionel Sambuc 	}
770433d6423SLionel Sambuc 
771433d6423SLionel Sambuc #ifdef BIX
772433d6423SLionel Sambuc 	if ((fout=fopen("scratchpad", openmode)) == NULL)
773433d6423SLionel Sambuc 		return ERROR;
774433d6423SLionel Sambuc 	return OK;
775433d6423SLionel Sambuc #else
776433d6423SLionel Sambuc 
777433d6423SLionel Sambuc 	else {		/* File coming from CP/M system */
778433d6423SLionel Sambuc 		for (p=name; *p; ++p)		/* change / to _ */
779433d6423SLionel Sambuc 			if ( *p == '/')
780433d6423SLionel Sambuc 				*p = '_';
781433d6423SLionel Sambuc 
782433d6423SLionel Sambuc 		if ( *--p == '.')		/* zap trailing period */
783433d6423SLionel Sambuc 			*p = 0;
784433d6423SLionel Sambuc 	}
785433d6423SLionel Sambuc 
786433d6423SLionel Sambuc #ifndef vax11c
787433d6423SLionel Sambuc 	if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
788433d6423SLionel Sambuc 	  && !(Filemode&UNIXFILE))
789433d6423SLionel Sambuc 		uncaps(name);
790433d6423SLionel Sambuc #endif
791433d6423SLionel Sambuc 	if (Topipe > 0) {
792433d6423SLionel Sambuc 		sprintf(Pathname, "%s %s", Progname+2, name);
793433d6423SLionel Sambuc 		if (Verbose)
794433d6423SLionel Sambuc 			fprintf(stderr,  "Topipe: %s %s\n",
795433d6423SLionel Sambuc 			  Pathname, Thisbinary?"BIN":"ASCII");
796433d6423SLionel Sambuc #ifndef vax11c
797433d6423SLionel Sambuc 		if ((fout=popen(Pathname, "w")) == NULL)
798433d6423SLionel Sambuc 			return ERROR;
799433d6423SLionel Sambuc #endif
800433d6423SLionel Sambuc 	} else {
801433d6423SLionel Sambuc 		strcpy(Pathname, name);
802433d6423SLionel Sambuc 		if (Verbose) {
803433d6423SLionel Sambuc 			fprintf(stderr,  "Receiving %s %s %s\n",
804433d6423SLionel Sambuc 			  name, Thisbinary?"BIN":"ASCII", openmode);
805433d6423SLionel Sambuc 		}
806433d6423SLionel Sambuc 		checkpath(name);
807433d6423SLionel Sambuc 		if (Nflag)
808433d6423SLionel Sambuc 			name = "/dev/null";
809433d6423SLionel Sambuc #ifndef vax11c
810433d6423SLionel Sambuc #ifdef OMEN
811433d6423SLionel Sambuc 		if (name[0] == '!' || name[0] == '|') {
812433d6423SLionel Sambuc 			if ( !(fout = popen(name+1, "w"))) {
813433d6423SLionel Sambuc 				return ERROR;
814433d6423SLionel Sambuc 			}
815433d6423SLionel Sambuc 			Topipe = -1;  return(OK);
816433d6423SLionel Sambuc 		}
817433d6423SLionel Sambuc #endif
818433d6423SLionel Sambuc #endif
819433d6423SLionel Sambuc #ifdef MD
820433d6423SLionel Sambuc 		fout = fopen(name, openmode);
821433d6423SLionel Sambuc 		if ( !fout)
822433d6423SLionel Sambuc 			if (make_dirs(name))
823433d6423SLionel Sambuc 				fout = fopen(name, openmode);
824433d6423SLionel Sambuc #else
825433d6423SLionel Sambuc 		fout = fopen(name, openmode);
826433d6423SLionel Sambuc #endif
827433d6423SLionel Sambuc 		if ( !fout)
828433d6423SLionel Sambuc 			return ERROR;
829433d6423SLionel Sambuc 	}
830433d6423SLionel Sambuc 	return OK;
831433d6423SLionel Sambuc #endif /* BIX */
832433d6423SLionel Sambuc }
833433d6423SLionel Sambuc 
834433d6423SLionel Sambuc #ifdef MD
835433d6423SLionel Sambuc /*
836433d6423SLionel Sambuc  *  Directory-creating routines from Public Domain TAR by John Gilmore
837433d6423SLionel Sambuc  */
838433d6423SLionel Sambuc 
839433d6423SLionel Sambuc /*
840433d6423SLionel Sambuc  * After a file/link/symlink/dir creation has failed, see if
841433d6423SLionel Sambuc  * it's because some required directory was not present, and if
842433d6423SLionel Sambuc  * so, create all required dirs.
843433d6423SLionel Sambuc  */
make_dirs(char * pathname)844433d6423SLionel Sambuc int make_dirs(char *pathname)
845433d6423SLionel Sambuc {
846433d6423SLionel Sambuc 	register char *p;		/* Points into path */
847433d6423SLionel Sambuc 	int madeone = 0;		/* Did we do anything yet? */
848433d6423SLionel Sambuc 	int save_errno = errno;		/* Remember caller's errno */
849433d6423SLionel Sambuc 	char *strchr();
850433d6423SLionel Sambuc 
851433d6423SLionel Sambuc 	if (errno != ENOENT)
852433d6423SLionel Sambuc 		return 0;		/* Not our problem */
853433d6423SLionel Sambuc 
854433d6423SLionel Sambuc 	for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
855433d6423SLionel Sambuc 		/* Avoid mkdir of empty string, if leading or double '/' */
856433d6423SLionel Sambuc 		if (p == pathname || p[-1] == '/')
857433d6423SLionel Sambuc 			continue;
858433d6423SLionel Sambuc 		/* Avoid mkdir where last part of path is '.' */
859433d6423SLionel Sambuc 		if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
860433d6423SLionel Sambuc 			continue;
861433d6423SLionel Sambuc 		*p = 0;				/* Truncate the path there */
862433d6423SLionel Sambuc 		if ( !makedir(pathname, 0777)) {	/* Try to create it as a dir */
863433d6423SLionel Sambuc 			vfile("Made directory %s\n", pathname);
864433d6423SLionel Sambuc 			madeone++;		/* Remember if we made one */
865433d6423SLionel Sambuc 			*p = '/';
866433d6423SLionel Sambuc 			continue;
867433d6423SLionel Sambuc 		}
868433d6423SLionel Sambuc 		*p = '/';
869433d6423SLionel Sambuc 		if (errno == EEXIST)		/* Directory already exists */
870433d6423SLionel Sambuc 			continue;
871433d6423SLionel Sambuc 		/*
872433d6423SLionel Sambuc 		 * Some other error in the makedir.  We return to the caller.
873433d6423SLionel Sambuc 		 */
874433d6423SLionel Sambuc 		break;
875433d6423SLionel Sambuc 	}
876433d6423SLionel Sambuc 	errno = save_errno;		/* Restore caller's errno */
877433d6423SLionel Sambuc 	return madeone;			/* Tell them to retry if we made one */
878433d6423SLionel Sambuc }
879433d6423SLionel Sambuc 
880433d6423SLionel Sambuc #if (MD != 2)
881433d6423SLionel Sambuc #define	TERM_SIGNAL(status)	((status) & 0x7F)
882433d6423SLionel Sambuc #define TERM_COREDUMP(status)	(((status) & 0x80) != 0)
883433d6423SLionel Sambuc #define TERM_VALUE(status)	((status) >> 8)
884433d6423SLionel Sambuc /*
885433d6423SLionel Sambuc  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
886433d6423SLionel Sambuc  */
makedir(char * dpath,int dmode)887433d6423SLionel Sambuc int makedir(char *dpath, int dmode)
888433d6423SLionel Sambuc {
889433d6423SLionel Sambuc 	int cpid, status;
890433d6423SLionel Sambuc 	struct stat statbuf;
891433d6423SLionel Sambuc 
892433d6423SLionel Sambuc 	if (stat(dpath,&statbuf) == 0) {
893433d6423SLionel Sambuc 		errno = EEXIST;		/* Stat worked, so it already exists */
894433d6423SLionel Sambuc 		return -1;
895433d6423SLionel Sambuc 	}
896433d6423SLionel Sambuc 
897433d6423SLionel Sambuc 	/* If stat fails for a reason other than non-existence, return error */
898433d6423SLionel Sambuc 	if (errno != ENOENT) return -1;
899433d6423SLionel Sambuc 
900433d6423SLionel Sambuc 	switch (cpid = fork()) {
901433d6423SLionel Sambuc 
902433d6423SLionel Sambuc 	case -1:			/* Error in fork() */
903433d6423SLionel Sambuc 		return(-1);		/* Errno is set already */
904433d6423SLionel Sambuc 
905433d6423SLionel Sambuc 	case 0:				/* Child process */
906433d6423SLionel Sambuc 		/*
907433d6423SLionel Sambuc 		 * Cheap hack to set mode of new directory.  Since this
908433d6423SLionel Sambuc 		 * child process is going away anyway, we zap its umask.
909433d6423SLionel Sambuc 		 * FIXME, this won't suffice to set SUID, SGID, etc. on this
910433d6423SLionel Sambuc 		 * directory.  Does anybody care?
911433d6423SLionel Sambuc 		 */
912433d6423SLionel Sambuc 		status = umask(0);	/* Get current umask */
913433d6423SLionel Sambuc 		status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
914433d6423SLionel Sambuc 		execl("/bin/mkdir", "mkdir", dpath, (char *)0);
915433d6423SLionel Sambuc 		_exit(-1);		/* Can't exec /bin/mkdir */
916433d6423SLionel Sambuc 
917433d6423SLionel Sambuc 	default:			/* Parent process */
918433d6423SLionel Sambuc 		while (cpid != wait(&status)) ;	/* Wait for kid to finish */
919433d6423SLionel Sambuc 	}
920433d6423SLionel Sambuc 
921433d6423SLionel Sambuc 	if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
922433d6423SLionel Sambuc 		errno = EIO;		/* We don't know why, but */
923433d6423SLionel Sambuc 		return -1;		/* /bin/mkdir failed */
924433d6423SLionel Sambuc 	}
925433d6423SLionel Sambuc 
926433d6423SLionel Sambuc 	return 0;
927433d6423SLionel Sambuc }
928433d6423SLionel Sambuc #endif /* MD != 2 */
929433d6423SLionel Sambuc #endif /* MD */
930433d6423SLionel Sambuc 
931433d6423SLionel Sambuc /*
932433d6423SLionel Sambuc  * Putsec writes the n characters of buf to receive file fout.
933433d6423SLionel Sambuc  *  If not in binary mode, carriage returns, and all characters
934433d6423SLionel Sambuc  *  starting with CPMEOF are discarded.
935433d6423SLionel Sambuc  */
putsec(char * buf,int n)936433d6423SLionel Sambuc int putsec(char *buf, int n)
937433d6423SLionel Sambuc {
938433d6423SLionel Sambuc 	register char *p;
939433d6423SLionel Sambuc 
940433d6423SLionel Sambuc 	if (n == 0)
941433d6423SLionel Sambuc 		return OK;
942433d6423SLionel Sambuc 	if (Thisbinary) {
943433d6423SLionel Sambuc 		for (p=buf; --n>=0; )
944433d6423SLionel Sambuc 			putc( *p++, fout);
945433d6423SLionel Sambuc 	}
946433d6423SLionel Sambuc 	else {
947433d6423SLionel Sambuc 		if (Eofseen)
948433d6423SLionel Sambuc 			return OK;
949433d6423SLionel Sambuc 		for (p=buf; --n>=0; ++p ) {
950433d6423SLionel Sambuc 			if ( *p == '\r')
951433d6423SLionel Sambuc 				continue;
952433d6423SLionel Sambuc 			if (*p == CPMEOF) {
953433d6423SLionel Sambuc 				Eofseen=TRUE; return OK;
954433d6423SLionel Sambuc 			}
955433d6423SLionel Sambuc 			putc(*p ,fout);
956433d6423SLionel Sambuc 		}
957433d6423SLionel Sambuc 	}
958433d6423SLionel Sambuc 	return OK;
959433d6423SLionel Sambuc }
960433d6423SLionel Sambuc 
961433d6423SLionel Sambuc #ifndef vax11c
962433d6423SLionel Sambuc /*
963433d6423SLionel Sambuc  *  Send a character to modem.  Small is beautiful.
964433d6423SLionel Sambuc  */
sendline(int c)965433d6423SLionel Sambuc void sendline(int c)
966433d6423SLionel Sambuc {
967433d6423SLionel Sambuc 	char d;
968433d6423SLionel Sambuc 
969433d6423SLionel Sambuc 	d = c;
970433d6423SLionel Sambuc 	if (Verbose>6)
971433d6423SLionel Sambuc 		fprintf(stderr, "Sendline: %x\n", c);
972433d6423SLionel Sambuc 	write(1, &d, 1);
973433d6423SLionel Sambuc }
974433d6423SLionel Sambuc 
flushmo()975433d6423SLionel Sambuc void flushmo() {}
976433d6423SLionel Sambuc #endif
977433d6423SLionel Sambuc 
978433d6423SLionel Sambuc 
979433d6423SLionel Sambuc 
980433d6423SLionel Sambuc 
981433d6423SLionel Sambuc 
982433d6423SLionel Sambuc /* make string s lower case */
uncaps(char * s)983433d6423SLionel Sambuc void uncaps(char *s)
984433d6423SLionel Sambuc {
985433d6423SLionel Sambuc 	for ( ; *s; ++s)
986433d6423SLionel Sambuc 		if (isupper(*s))
987433d6423SLionel Sambuc 			*s = tolower(*s);
988433d6423SLionel Sambuc }
989433d6423SLionel Sambuc /*
990433d6423SLionel Sambuc  * IsAnyLower returns TRUE if string s has lower case letters.
991433d6423SLionel Sambuc  */
IsAnyLower(char * s)992433d6423SLionel Sambuc int IsAnyLower(char *s)
993433d6423SLionel Sambuc {
994433d6423SLionel Sambuc 	for ( ; *s; ++s)
995433d6423SLionel Sambuc 		if (islower(*s))
996433d6423SLionel Sambuc 			return TRUE;
997433d6423SLionel Sambuc 	return FALSE;
998433d6423SLionel Sambuc }
999433d6423SLionel Sambuc 
1000433d6423SLionel Sambuc /*
1001433d6423SLionel Sambuc  * substr(string, token) searches for token in string s
1002433d6423SLionel Sambuc  * returns pointer to token within string if found, NULL otherwise
1003433d6423SLionel Sambuc  */
1004433d6423SLionel Sambuc char *
substr(char * s,char * t)1005433d6423SLionel Sambuc substr(char *s, char *t)
1006433d6423SLionel Sambuc {
1007433d6423SLionel Sambuc 	register char *ss,*tt;
1008433d6423SLionel Sambuc 	/* search for first char of token */
1009433d6423SLionel Sambuc 	for (ss=s; *s; s++)
1010433d6423SLionel Sambuc 		if (*s == *t)
1011433d6423SLionel Sambuc 			/* compare token with substring */
1012433d6423SLionel Sambuc 			for (ss=s,tt=t; ;) {
1013433d6423SLionel Sambuc 				if (*tt == 0)
1014433d6423SLionel Sambuc 					return s;
1015433d6423SLionel Sambuc 				if (*ss++ != *tt++)
1016433d6423SLionel Sambuc 					break;
1017433d6423SLionel Sambuc 			}
1018433d6423SLionel Sambuc 	return (char *)NULL;
1019433d6423SLionel Sambuc }
1020433d6423SLionel Sambuc 
1021433d6423SLionel Sambuc /*
1022433d6423SLionel Sambuc  * Log an error
1023433d6423SLionel Sambuc  */
1024433d6423SLionel Sambuc /*VARARGS1*/
zperr(char * s,char * p,char * u)1025433d6423SLionel Sambuc void zperr(char *s, char *p, char *u)
1026433d6423SLionel Sambuc {
1027433d6423SLionel Sambuc 	if (Verbose <= 0)
1028433d6423SLionel Sambuc 		return;
1029433d6423SLionel Sambuc 	fprintf(stderr, "Retry %d: ", errors);
1030433d6423SLionel Sambuc 	fprintf(stderr, s, p, u);
1031433d6423SLionel Sambuc 	fprintf(stderr, "\n");
1032433d6423SLionel Sambuc }
1033433d6423SLionel Sambuc 
1034433d6423SLionel Sambuc /* send cancel string to get the other end to shut up */
canit()1035433d6423SLionel Sambuc void canit()
1036433d6423SLionel Sambuc {
1037433d6423SLionel Sambuc 	static char canistr[] = {
1038433d6423SLionel Sambuc 	 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
1039433d6423SLionel Sambuc 	};
1040433d6423SLionel Sambuc 
1041433d6423SLionel Sambuc #ifdef vax11c
1042433d6423SLionel Sambuc 	raw_wbuf(strlen(canistr), canistr);
1043433d6423SLionel Sambuc 	purgeline();
1044433d6423SLionel Sambuc #else
1045*d0055759SDavid van Moolenbroek 	printf("%s", canistr);
1046433d6423SLionel Sambuc 	Lleft=0;	/* Do read next time ... */
1047433d6423SLionel Sambuc 	fflush(stdout);
1048433d6423SLionel Sambuc #endif
1049433d6423SLionel Sambuc }
1050433d6423SLionel Sambuc 
1051433d6423SLionel Sambuc 
report(int sct)1052433d6423SLionel Sambuc void report(int sct)
1053433d6423SLionel Sambuc {
1054433d6423SLionel Sambuc 	if (Verbose>1)
1055433d6423SLionel Sambuc 		fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
1056433d6423SLionel Sambuc }
1057433d6423SLionel Sambuc 
1058433d6423SLionel Sambuc #ifndef vax11c
1059433d6423SLionel Sambuc /*
1060433d6423SLionel Sambuc  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
1061433d6423SLionel Sambuc  * If called as [-][dir/../]rzCOMMAND set the pipe flag
1062433d6423SLionel Sambuc  * If called as rb use YMODEM protocol
1063433d6423SLionel Sambuc  */
chkinvok(char * s)1064433d6423SLionel Sambuc void chkinvok(char *s)
1065433d6423SLionel Sambuc {
1066433d6423SLionel Sambuc 	register char *p;
1067433d6423SLionel Sambuc 
1068433d6423SLionel Sambuc 	p = s;
1069433d6423SLionel Sambuc 	while (*p == '-')
1070433d6423SLionel Sambuc 		s = ++p;
1071433d6423SLionel Sambuc 	while (*p)
1072433d6423SLionel Sambuc 		if (*p++ == '/')
1073433d6423SLionel Sambuc 			s = p;
1074433d6423SLionel Sambuc 	if (*s == 'v') {
1075433d6423SLionel Sambuc 		Verbose=1; ++s;
1076433d6423SLionel Sambuc 	}
1077433d6423SLionel Sambuc 	Progname = s;
1078433d6423SLionel Sambuc 	if (s[0]=='r' && s[1]=='z')
1079433d6423SLionel Sambuc 		Batch = TRUE;
1080433d6423SLionel Sambuc 	if (s[0]=='r' && s[1]=='b')
1081433d6423SLionel Sambuc 		Batch = Nozmodem = TRUE;
1082433d6423SLionel Sambuc 	if (s[2] && s[0]=='r' && s[1]=='b')
1083433d6423SLionel Sambuc 		Topipe = 1;
1084433d6423SLionel Sambuc 	if (s[2] && s[0]=='r' && s[1]=='z')
1085433d6423SLionel Sambuc 		Topipe = 1;
1086433d6423SLionel Sambuc }
1087433d6423SLionel Sambuc #endif
1088433d6423SLionel Sambuc 
1089433d6423SLionel Sambuc /*
1090433d6423SLionel Sambuc  * Totalitarian Communist pathname processing
1091433d6423SLionel Sambuc  */
checkpath(char * name)1092433d6423SLionel Sambuc void checkpath(char *name)
1093433d6423SLionel Sambuc {
1094433d6423SLionel Sambuc 	if (Restricted) {
1095433d6423SLionel Sambuc 		if (fopen(name, "r") != NULL) {
1096433d6423SLionel Sambuc 			canit();
1097433d6423SLionel Sambuc 			fprintf(stderr, "\r\nrz: %s exists\n", name);
1098433d6423SLionel Sambuc 			bibi(-1);
1099433d6423SLionel Sambuc 		}
1100433d6423SLionel Sambuc 		/* restrict pathnames to current tree or uucppublic */
1101433d6423SLionel Sambuc 		if ( substr(name, "../")
1102433d6423SLionel Sambuc 		 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
1103433d6423SLionel Sambuc 			canit();
1104433d6423SLionel Sambuc 			fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
1105433d6423SLionel Sambuc 			bibi(-1);
1106433d6423SLionel Sambuc 		}
1107433d6423SLionel Sambuc 	}
1108433d6423SLionel Sambuc }
1109433d6423SLionel Sambuc 
1110433d6423SLionel Sambuc /*
1111433d6423SLionel Sambuc  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
1112433d6423SLionel Sambuc  *  Handles ZSINIT frame
1113433d6423SLionel Sambuc  *  Return ZFILE if Zmodem filename received, -1 on error,
1114433d6423SLionel Sambuc  *   ZCOMPL if transaction finished,  else 0
1115433d6423SLionel Sambuc  */
tryz()1116433d6423SLionel Sambuc int tryz()
1117433d6423SLionel Sambuc {
1118433d6423SLionel Sambuc 	register int c, n;
1119433d6423SLionel Sambuc 	register int cmdzack1flg;
1120433d6423SLionel Sambuc 
1121433d6423SLionel Sambuc 	if (Nozmodem)		/* Check for "rb" program name */
1122433d6423SLionel Sambuc 		return 0;
1123433d6423SLionel Sambuc 
1124433d6423SLionel Sambuc 
1125433d6423SLionel Sambuc 	for (n=Zmodem?15:5; --n>=0; ) {
1126433d6423SLionel Sambuc 		/* Set buffer length (0) and capability flags */
1127433d6423SLionel Sambuc #ifdef SEGMENTS
1128433d6423SLionel Sambuc 		stohdr(SEGMENTS*1024L);
1129433d6423SLionel Sambuc #else
1130433d6423SLionel Sambuc 		stohdr(0L);
1131433d6423SLionel Sambuc #endif
1132433d6423SLionel Sambuc #ifdef CANBREAK
1133433d6423SLionel Sambuc 		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
1134433d6423SLionel Sambuc #else
1135433d6423SLionel Sambuc 		Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
1136433d6423SLionel Sambuc #endif
1137433d6423SLionel Sambuc 		if (Zctlesc)
1138433d6423SLionel Sambuc 			Txhdr[ZF0] |= TESCCTL;
1139433d6423SLionel Sambuc 		zshhdr(tryzhdrtype, Txhdr);
1140433d6423SLionel Sambuc 		if (tryzhdrtype == ZSKIP)	/* Don't skip too far */
1141433d6423SLionel Sambuc 			tryzhdrtype = ZRINIT;	/* CAF 8-21-87 */
1142433d6423SLionel Sambuc again:
1143433d6423SLionel Sambuc 		switch (zgethdr(Rxhdr, 0)) {
1144433d6423SLionel Sambuc 		case ZRQINIT:
1145433d6423SLionel Sambuc 			continue;
1146433d6423SLionel Sambuc 		case ZEOF:
1147433d6423SLionel Sambuc 			continue;
1148433d6423SLionel Sambuc 		case TIMEOUT:
1149433d6423SLionel Sambuc 			continue;
1150433d6423SLionel Sambuc 		case ZFILE:
1151433d6423SLionel Sambuc 			zconv = Rxhdr[ZF0];
1152433d6423SLionel Sambuc 			zmanag = Rxhdr[ZF1];
1153433d6423SLionel Sambuc 			ztrans = Rxhdr[ZF2];
1154433d6423SLionel Sambuc 			tryzhdrtype = ZRINIT;
1155433d6423SLionel Sambuc 			c = zrdata(secbuf, 1024);
1156433d6423SLionel Sambuc 			mode(3);
1157433d6423SLionel Sambuc 			if (c == GOTCRCW)
1158433d6423SLionel Sambuc 				return ZFILE;
1159433d6423SLionel Sambuc 			zshhdr(ZNAK, Txhdr);
1160433d6423SLionel Sambuc 			goto again;
1161433d6423SLionel Sambuc 		case ZSINIT:
1162433d6423SLionel Sambuc 			Zctlesc = TESCCTL & Rxhdr[ZF0];
1163433d6423SLionel Sambuc 			if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
1164433d6423SLionel Sambuc 				stohdr(1L);
1165433d6423SLionel Sambuc 				zshhdr(ZACK, Txhdr);
1166433d6423SLionel Sambuc 				goto again;
1167433d6423SLionel Sambuc 			}
1168433d6423SLionel Sambuc 			zshhdr(ZNAK, Txhdr);
1169433d6423SLionel Sambuc 			goto again;
1170433d6423SLionel Sambuc 		case ZFREECNT:
1171433d6423SLionel Sambuc 			stohdr(getfree());
1172433d6423SLionel Sambuc 			zshhdr(ZACK, Txhdr);
1173433d6423SLionel Sambuc 			goto again;
1174433d6423SLionel Sambuc 		case ZCOMMAND:
1175433d6423SLionel Sambuc #ifdef vax11c
1176433d6423SLionel Sambuc 			return ERROR;
1177433d6423SLionel Sambuc #else
1178433d6423SLionel Sambuc 			cmdzack1flg = Rxhdr[ZF0];
1179433d6423SLionel Sambuc 			if (zrdata(secbuf, 1024) == GOTCRCW) {
1180433d6423SLionel Sambuc 				if (cmdzack1flg & ZCACK1)
1181433d6423SLionel Sambuc 					stohdr(0L);
1182433d6423SLionel Sambuc 				else
1183433d6423SLionel Sambuc 					stohdr((long)sys2(secbuf));
1184433d6423SLionel Sambuc 				purgeline();	/* dump impatient questions */
1185433d6423SLionel Sambuc 				do {
1186433d6423SLionel Sambuc 					zshhdr(ZCOMPL, Txhdr);
1187433d6423SLionel Sambuc 				}
1188433d6423SLionel Sambuc 				while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
1189433d6423SLionel Sambuc 				ackbibi();
1190433d6423SLionel Sambuc 				if (cmdzack1flg & ZCACK1)
1191433d6423SLionel Sambuc 					exec2(secbuf);
1192433d6423SLionel Sambuc 				return ZCOMPL;
1193433d6423SLionel Sambuc 			}
1194433d6423SLionel Sambuc 			zshhdr(ZNAK, Txhdr); goto again;
1195433d6423SLionel Sambuc #endif
1196433d6423SLionel Sambuc 		case ZCOMPL:
1197433d6423SLionel Sambuc 			goto again;
1198433d6423SLionel Sambuc 		default:
1199433d6423SLionel Sambuc 			continue;
1200433d6423SLionel Sambuc 		case ZFIN:
1201433d6423SLionel Sambuc 			ackbibi(); return ZCOMPL;
1202433d6423SLionel Sambuc 		case ZCAN:
1203433d6423SLionel Sambuc 			return ERROR;
1204433d6423SLionel Sambuc 		}
1205433d6423SLionel Sambuc 	}
1206433d6423SLionel Sambuc 	return 0;
1207433d6423SLionel Sambuc }
1208433d6423SLionel Sambuc 
1209433d6423SLionel Sambuc /*
1210433d6423SLionel Sambuc  * Receive 1 or more files with ZMODEM protocol
1211433d6423SLionel Sambuc  */
rzfiles()1212433d6423SLionel Sambuc int rzfiles()
1213433d6423SLionel Sambuc {
1214433d6423SLionel Sambuc 	register int c;
1215433d6423SLionel Sambuc 
1216433d6423SLionel Sambuc 	for (;;) {
1217433d6423SLionel Sambuc 		switch (c = rzfile()) {
1218433d6423SLionel Sambuc 		case ZEOF:
1219433d6423SLionel Sambuc 		case ZSKIP:
1220433d6423SLionel Sambuc 			switch (tryz()) {
1221433d6423SLionel Sambuc 			case ZCOMPL:
1222433d6423SLionel Sambuc 				return OK;
1223433d6423SLionel Sambuc 			default:
1224433d6423SLionel Sambuc 				return ERROR;
1225433d6423SLionel Sambuc 			case ZFILE:
1226433d6423SLionel Sambuc 				break;
1227433d6423SLionel Sambuc 			}
1228433d6423SLionel Sambuc 			continue;
1229433d6423SLionel Sambuc 		default:
1230433d6423SLionel Sambuc 			return c;
1231433d6423SLionel Sambuc 		case ERROR:
1232433d6423SLionel Sambuc 			return ERROR;
1233433d6423SLionel Sambuc 		}
1234433d6423SLionel Sambuc 	}
1235433d6423SLionel Sambuc }
1236433d6423SLionel Sambuc 
1237433d6423SLionel Sambuc /*
1238433d6423SLionel Sambuc  * Receive a file with ZMODEM protocol
1239433d6423SLionel Sambuc  *  Assumes file name frame is in secbuf
1240433d6423SLionel Sambuc  */
rzfile()1241433d6423SLionel Sambuc int rzfile()
1242433d6423SLionel Sambuc {
1243433d6423SLionel Sambuc 	register int c, n;
1244433d6423SLionel Sambuc 	long rxbytes;
1245433d6423SLionel Sambuc 
1246433d6423SLionel Sambuc 	Eofseen=FALSE;
1247433d6423SLionel Sambuc 	if (procheader(secbuf) == ERROR) {
1248433d6423SLionel Sambuc 		return (tryzhdrtype = ZSKIP);
1249433d6423SLionel Sambuc 	}
1250433d6423SLionel Sambuc 
1251433d6423SLionel Sambuc 	n = 20; rxbytes = 0l;
1252433d6423SLionel Sambuc 
1253433d6423SLionel Sambuc 	for (;;) {
1254433d6423SLionel Sambuc #ifdef SEGMENTS
1255433d6423SLionel Sambuc 		chinseg = 0;
1256433d6423SLionel Sambuc #endif
1257433d6423SLionel Sambuc 		stohdr(rxbytes);
1258433d6423SLionel Sambuc 		zshhdr(ZRPOS, Txhdr);
1259433d6423SLionel Sambuc nxthdr:
1260433d6423SLionel Sambuc 		switch (c = zgethdr(Rxhdr, 0)) {
1261433d6423SLionel Sambuc 		default:
1262433d6423SLionel Sambuc 			vfile("rzfile: zgethdr returned %d", c);
1263433d6423SLionel Sambuc 			return ERROR;
1264433d6423SLionel Sambuc 		case ZNAK:
1265433d6423SLionel Sambuc 		case TIMEOUT:
1266433d6423SLionel Sambuc #ifdef SEGMENTS
1267433d6423SLionel Sambuc 			putsec(secbuf, chinseg);
1268433d6423SLionel Sambuc 			chinseg = 0;
1269433d6423SLionel Sambuc #endif
1270433d6423SLionel Sambuc 			if ( --n < 0) {
1271433d6423SLionel Sambuc 				vfile("rzfile: zgethdr returned %d", c);
1272433d6423SLionel Sambuc 				return ERROR;
1273433d6423SLionel Sambuc 			}
1274433d6423SLionel Sambuc 		case ZFILE:
1275433d6423SLionel Sambuc 			zrdata(secbuf, 1024);
1276433d6423SLionel Sambuc 			continue;
1277433d6423SLionel Sambuc 		case ZEOF:
1278433d6423SLionel Sambuc #ifdef SEGMENTS
1279433d6423SLionel Sambuc 			putsec(secbuf, chinseg);
1280433d6423SLionel Sambuc 			chinseg = 0;
1281433d6423SLionel Sambuc #endif
1282433d6423SLionel Sambuc 			if (rclhdr(Rxhdr) != rxbytes) {
1283433d6423SLionel Sambuc 				/*
1284433d6423SLionel Sambuc 				 * Ignore eof if it's at wrong place - force
1285433d6423SLionel Sambuc 				 *  a timeout because the eof might have gone
1286433d6423SLionel Sambuc 				 *  out before we sent our zrpos.
1287433d6423SLionel Sambuc 				 */
1288433d6423SLionel Sambuc 				errors = 0;  goto nxthdr;
1289433d6423SLionel Sambuc 			}
1290433d6423SLionel Sambuc 			if (closeit()) {
1291433d6423SLionel Sambuc 				tryzhdrtype = ZFERR;
1292433d6423SLionel Sambuc 				vfile("rzfile: closeit returned <> 0");
1293433d6423SLionel Sambuc 				return ERROR;
1294433d6423SLionel Sambuc 			}
1295433d6423SLionel Sambuc 			vfile("rzfile: normal EOF");
1296433d6423SLionel Sambuc 			return c;
1297433d6423SLionel Sambuc 		case ERROR:	/* Too much garbage in header search error */
1298433d6423SLionel Sambuc #ifdef SEGMENTS
1299433d6423SLionel Sambuc 			putsec(secbuf, chinseg);
1300433d6423SLionel Sambuc 			chinseg = 0;
1301433d6423SLionel Sambuc #endif
1302433d6423SLionel Sambuc 			if ( --n < 0) {
1303433d6423SLionel Sambuc 				vfile("rzfile: zgethdr returned %d", c);
1304433d6423SLionel Sambuc 				return ERROR;
1305433d6423SLionel Sambuc 			}
1306433d6423SLionel Sambuc 			zmputs(Attn);
1307433d6423SLionel Sambuc 			continue;
1308433d6423SLionel Sambuc 		case ZSKIP:
1309433d6423SLionel Sambuc #ifdef SEGMENTS
1310433d6423SLionel Sambuc 			putsec(secbuf, chinseg);
1311433d6423SLionel Sambuc 			chinseg = 0;
1312433d6423SLionel Sambuc #endif
1313433d6423SLionel Sambuc 			closeit();
1314433d6423SLionel Sambuc 			vfile("rzfile: Sender SKIPPED file");
1315433d6423SLionel Sambuc 			return c;
1316433d6423SLionel Sambuc 		case ZDATA:
1317433d6423SLionel Sambuc 			if (rclhdr(Rxhdr) != rxbytes) {
1318433d6423SLionel Sambuc 				if ( --n < 0) {
1319433d6423SLionel Sambuc 					return ERROR;
1320433d6423SLionel Sambuc 				}
1321433d6423SLionel Sambuc #ifdef SEGMENTS
1322433d6423SLionel Sambuc 				putsec(secbuf, chinseg);
1323433d6423SLionel Sambuc 				chinseg = 0;
1324433d6423SLionel Sambuc #endif
1325433d6423SLionel Sambuc 				zmputs(Attn);  continue;
1326433d6423SLionel Sambuc 			}
1327433d6423SLionel Sambuc moredata:
1328433d6423SLionel Sambuc 			if (Verbose>1)
1329433d6423SLionel Sambuc 				fprintf(stderr, "\r%7ld ZMODEM%s    ",
1330433d6423SLionel Sambuc 				  rxbytes, Crc32?" CRC-32":"");
1331433d6423SLionel Sambuc #ifdef SEGMENTS
1332433d6423SLionel Sambuc 			if (chinseg >= (1024 * SEGMENTS)) {
1333433d6423SLionel Sambuc 				putsec(secbuf, chinseg);
1334433d6423SLionel Sambuc 				chinseg = 0;
1335433d6423SLionel Sambuc 			}
1336433d6423SLionel Sambuc 			switch (c = zrdata(secbuf+chinseg, 1024))
1337433d6423SLionel Sambuc #else
1338433d6423SLionel Sambuc 			switch (c = zrdata(secbuf, 1024))
1339433d6423SLionel Sambuc #endif
1340433d6423SLionel Sambuc 			{
1341433d6423SLionel Sambuc 			case ZCAN:
1342433d6423SLionel Sambuc #ifdef SEGMENTS
1343433d6423SLionel Sambuc 				putsec(secbuf, chinseg);
1344433d6423SLionel Sambuc 				chinseg = 0;
1345433d6423SLionel Sambuc #endif
1346433d6423SLionel Sambuc 				vfile("rzfile: zgethdr returned %d", c);
1347433d6423SLionel Sambuc 				return ERROR;
1348433d6423SLionel Sambuc 			case ERROR:	/* CRC error */
1349433d6423SLionel Sambuc #ifdef SEGMENTS
1350433d6423SLionel Sambuc 				putsec(secbuf, chinseg);
1351433d6423SLionel Sambuc 				chinseg = 0;
1352433d6423SLionel Sambuc #endif
1353433d6423SLionel Sambuc 				if ( --n < 0) {
1354433d6423SLionel Sambuc 					vfile("rzfile: zgethdr returned %d", c);
1355433d6423SLionel Sambuc 					return ERROR;
1356433d6423SLionel Sambuc 				}
1357433d6423SLionel Sambuc 				zmputs(Attn);
1358433d6423SLionel Sambuc 				continue;
1359433d6423SLionel Sambuc 			case TIMEOUT:
1360433d6423SLionel Sambuc #ifdef SEGMENTS
1361433d6423SLionel Sambuc 				putsec(secbuf, chinseg);
1362433d6423SLionel Sambuc 				chinseg = 0;
1363433d6423SLionel Sambuc #endif
1364433d6423SLionel Sambuc 				if ( --n < 0) {
1365433d6423SLionel Sambuc 					vfile("rzfile: zgethdr returned %d", c);
1366433d6423SLionel Sambuc 					return ERROR;
1367433d6423SLionel Sambuc 				}
1368433d6423SLionel Sambuc 				continue;
1369433d6423SLionel Sambuc 			case GOTCRCW:
1370433d6423SLionel Sambuc 				n = 20;
1371433d6423SLionel Sambuc #ifdef SEGMENTS
1372433d6423SLionel Sambuc 				chinseg += Rxcount;
1373433d6423SLionel Sambuc 				putsec(secbuf, chinseg);
1374433d6423SLionel Sambuc 				chinseg = 0;
1375433d6423SLionel Sambuc #else
1376433d6423SLionel Sambuc 				putsec(secbuf, Rxcount);
1377433d6423SLionel Sambuc #endif
1378433d6423SLionel Sambuc 				rxbytes += Rxcount;
1379433d6423SLionel Sambuc 				stohdr(rxbytes);
1380433d6423SLionel Sambuc 				zshhdr(ZACK, Txhdr);
1381433d6423SLionel Sambuc 				sendline(XON);
1382433d6423SLionel Sambuc 				goto nxthdr;
1383433d6423SLionel Sambuc 			case GOTCRCQ:
1384433d6423SLionel Sambuc 				n = 20;
1385433d6423SLionel Sambuc #ifdef SEGMENTS
1386433d6423SLionel Sambuc 				chinseg += Rxcount;
1387433d6423SLionel Sambuc #else
1388433d6423SLionel Sambuc 				putsec(secbuf, Rxcount);
1389433d6423SLionel Sambuc #endif
1390433d6423SLionel Sambuc 				rxbytes += Rxcount;
1391433d6423SLionel Sambuc 				stohdr(rxbytes);
1392433d6423SLionel Sambuc 				zshhdr(ZACK, Txhdr);
1393433d6423SLionel Sambuc 				goto moredata;
1394433d6423SLionel Sambuc 			case GOTCRCG:
1395433d6423SLionel Sambuc 				n = 20;
1396433d6423SLionel Sambuc #ifdef SEGMENTS
1397433d6423SLionel Sambuc 				chinseg += Rxcount;
1398433d6423SLionel Sambuc #else
1399433d6423SLionel Sambuc 				putsec(secbuf, Rxcount);
1400433d6423SLionel Sambuc #endif
1401433d6423SLionel Sambuc 				rxbytes += Rxcount;
1402433d6423SLionel Sambuc 				goto moredata;
1403433d6423SLionel Sambuc 			case GOTCRCE:
1404433d6423SLionel Sambuc 				n = 20;
1405433d6423SLionel Sambuc #ifdef SEGMENTS
1406433d6423SLionel Sambuc 				chinseg += Rxcount;
1407433d6423SLionel Sambuc #else
1408433d6423SLionel Sambuc 				putsec(secbuf, Rxcount);
1409433d6423SLionel Sambuc #endif
1410433d6423SLionel Sambuc 				rxbytes += Rxcount;
1411433d6423SLionel Sambuc 				goto nxthdr;
1412433d6423SLionel Sambuc 			}
1413433d6423SLionel Sambuc 		}
1414433d6423SLionel Sambuc 	}
1415433d6423SLionel Sambuc }
1416433d6423SLionel Sambuc 
1417433d6423SLionel Sambuc /*
1418433d6423SLionel Sambuc  * Send a string to the modem, processing for \336 (sleep 1 sec)
1419433d6423SLionel Sambuc  *   and \335 (break signal)
1420433d6423SLionel Sambuc  */
zmputs(char * s)1421433d6423SLionel Sambuc void zmputs(char *s)
1422433d6423SLionel Sambuc {
1423433d6423SLionel Sambuc 	register int c;
1424433d6423SLionel Sambuc 
1425433d6423SLionel Sambuc 	while (*s) {
1426433d6423SLionel Sambuc 		switch (c = *s++) {
1427433d6423SLionel Sambuc 		case '\336':
1428433d6423SLionel Sambuc 			sleep(1); continue;
1429433d6423SLionel Sambuc 		case '\335':
1430433d6423SLionel Sambuc 			sendbrk(); continue;
1431433d6423SLionel Sambuc 		default:
1432433d6423SLionel Sambuc 			sendline(c);
1433433d6423SLionel Sambuc 		}
1434433d6423SLionel Sambuc 	}
1435433d6423SLionel Sambuc }
1436433d6423SLionel Sambuc 
1437433d6423SLionel Sambuc /*
1438433d6423SLionel Sambuc  * Close the receive dataset, return OK or ERROR
1439433d6423SLionel Sambuc  */
closeit()1440433d6423SLionel Sambuc int closeit()
1441433d6423SLionel Sambuc {
1442433d6423SLionel Sambuc 	time_t q;
1443433d6423SLionel Sambuc 
1444433d6423SLionel Sambuc #ifndef vax11c
1445433d6423SLionel Sambuc 	if (Topipe) {
1446433d6423SLionel Sambuc 		if (pclose(fout)) {
1447433d6423SLionel Sambuc 			return ERROR;
1448433d6423SLionel Sambuc 		}
1449433d6423SLionel Sambuc 		return OK;
1450433d6423SLionel Sambuc 	}
1451433d6423SLionel Sambuc #endif
1452433d6423SLionel Sambuc 	if (fclose(fout)==ERROR) {
1453433d6423SLionel Sambuc 		fprintf(stderr, "file close ERROR\n");
1454433d6423SLionel Sambuc 		return ERROR;
1455433d6423SLionel Sambuc 	}
1456433d6423SLionel Sambuc #ifndef vax11c
1457433d6423SLionel Sambuc 	if (Modtime) {
1458433d6423SLionel Sambuc 		timep[0] = time(&q);
1459433d6423SLionel Sambuc 		timep[1] = Modtime;
1460433d6423SLionel Sambuc 		utime(Pathname, (struct utimbuf *) timep);
1461433d6423SLionel Sambuc 	}
1462433d6423SLionel Sambuc #endif
1463433d6423SLionel Sambuc 	if ((Filemode&S_IFMT) == S_IFREG)
1464433d6423SLionel Sambuc 		chmod(Pathname, (07777 & Filemode));
1465433d6423SLionel Sambuc 	return OK;
1466433d6423SLionel Sambuc }
1467433d6423SLionel Sambuc 
1468433d6423SLionel Sambuc /*
1469433d6423SLionel Sambuc  * Ack a ZFIN packet, let byegones be byegones
1470433d6423SLionel Sambuc  */
ackbibi()1471433d6423SLionel Sambuc void ackbibi()
1472433d6423SLionel Sambuc {
1473433d6423SLionel Sambuc 	register int n;
1474433d6423SLionel Sambuc 
1475433d6423SLionel Sambuc 	vfile("ackbibi:");
1476433d6423SLionel Sambuc 	Readnum = 1;
1477433d6423SLionel Sambuc 	stohdr(0L);
1478433d6423SLionel Sambuc 	for (n=3; --n>=0; ) {
1479433d6423SLionel Sambuc 		purgeline();
1480433d6423SLionel Sambuc 		zshhdr(ZFIN, Txhdr);
1481433d6423SLionel Sambuc 		switch (readline(100)) {
1482433d6423SLionel Sambuc 		case 'O':
1483433d6423SLionel Sambuc 			readline(1);	/* Discard 2nd 'O' */
1484433d6423SLionel Sambuc 			vfile("ackbibi complete");
1485433d6423SLionel Sambuc 			return;
1486433d6423SLionel Sambuc 		case RCDO:
1487433d6423SLionel Sambuc 			return;
1488433d6423SLionel Sambuc 		case TIMEOUT:
1489433d6423SLionel Sambuc 		default:
1490433d6423SLionel Sambuc 			break;
1491433d6423SLionel Sambuc 		}
1492433d6423SLionel Sambuc 	}
1493433d6423SLionel Sambuc }
1494433d6423SLionel Sambuc 
1495433d6423SLionel Sambuc 
1496433d6423SLionel Sambuc 
1497433d6423SLionel Sambuc /*
1498433d6423SLionel Sambuc  * Local console output simulation
1499433d6423SLionel Sambuc  */
bttyout(int c)1500433d6423SLionel Sambuc void bttyout(int c)
1501433d6423SLionel Sambuc {
1502433d6423SLionel Sambuc 	if (Verbose || Fromcu)
1503433d6423SLionel Sambuc 		putc(c, stderr);
1504433d6423SLionel Sambuc }
1505433d6423SLionel Sambuc 
1506433d6423SLionel Sambuc #ifndef vax11c
1507433d6423SLionel Sambuc /*
1508433d6423SLionel Sambuc  * Strip leading ! if present, do shell escape.
1509433d6423SLionel Sambuc  */
sys2(char * s)1510433d6423SLionel Sambuc int sys2(char *s)
1511433d6423SLionel Sambuc {
1512433d6423SLionel Sambuc 	if (*s == '!')
1513433d6423SLionel Sambuc 		++s;
1514433d6423SLionel Sambuc 	return system(s);
1515433d6423SLionel Sambuc }
1516433d6423SLionel Sambuc /*
1517433d6423SLionel Sambuc  * Strip leading ! if present, do exec.
1518433d6423SLionel Sambuc  */
exec2(char * s)1519433d6423SLionel Sambuc void exec2(char *s)
1520433d6423SLionel Sambuc {
1521433d6423SLionel Sambuc 	if (*s == '!')
1522433d6423SLionel Sambuc 		++s;
1523433d6423SLionel Sambuc 	mode(0);
1524433d6423SLionel Sambuc 	execl("/bin/sh", "sh", "-c", s);
1525433d6423SLionel Sambuc }
1526433d6423SLionel Sambuc #endif
1527433d6423SLionel Sambuc /* End of rz.c */
1528