xref: /original-bsd/usr.bin/uucp/uucico/cntrl.c (revision 5d3a6356)
1 #ifndef lint
2 static char sccsid[] = "@(#)cntrl.c	5.12	(Berkeley) 05/04/88";
3 #endif
4 
5 #include "uucp.h"
6 #include <sys/stat.h>
7 #include "uust.h"
8 
9 extern int errno;
10 extern int turntime;
11 int willturn;
12 int HaveSentHup = 0;
13 
14 struct Proto {
15 	char P_id;
16 	int (*P_turnon)();
17 	int (*P_rdmsg)();
18 	int (*P_wrmsg)();
19 	int (*P_rddata)();
20 	int (*P_wrdata)();
21 	int (*P_turnoff)();
22 };
23 
24 extern int gturnon(), gturnoff();
25 extern int grdmsg(), grddata();
26 extern int gwrmsg(), gwrdata();
27 extern int imsg(), omsg(), nullf();
28 #ifdef TCPIP
29 extern int twrmsg(), trdmsg();
30 extern int twrdata(), trddata();
31 #endif TCPIP
32 #ifdef PAD
33 extern int fturnon(), fturnoff();
34 extern int frdmsg(), frddata();
35 extern int fwrmsg(), fwrdata();
36 #endif PAD
37 
38 struct Proto Ptbl[]={
39 #ifdef TCPIP
40 	't', nullf, trdmsg, twrmsg, trddata, twrdata, nullf,
41 #endif TCPIP
42 #ifdef PAD
43 	'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff,
44 #endif PAD
45 	'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff,
46 	'\0'
47 };
48 
49 int (*Imsg)() = imsg, (*Omsg)() = omsg;
50 
51 int (*Rdmsg)()=imsg, (*Rddata)();
52 int (*Wrmsg)()=omsg, (*Wrdata)();
53 int (*Turnon)()=nullf, (*Turnoff)() = nullf;
54 
55 struct timeb Now, LastTurned, LastCheckedNoLogin;
56 
57 static char *YES = "Y";
58 static char *NO = "N";
59 
60 int TransferSucceeded = 1;
61 
62 /*  failure messages  */
63 #define EM_MAX		6
64 #define EM_LOCACC	"N1"	/* local access to file denied */
65 #define EM_RMTACC	"N2"	/* remote access to file/path denied */
66 #define EM_BADUUCP	"N3"	/* a bad uucp command was generated */
67 #define EM_NOTMP	"N4"	/* remote error - can't create temp */
68 #define EM_RMTCP	"N5"	/* can't copy to remote directory - file in public */
69 #define EM_LOCCP	"N6"	/* can't copy on local system */
70 
71 char *Em_msg[] = {
72 	"COPY FAILED (reason not given by remote)",
73 	"local access to file denied",
74 	"remote access to path/file denied",
75 	"system error - bad uucp command generated",
76 	"remote system can't create temp file",
77 	"can't copy to file/directory - file left in PUBDIR/user/file",
78 	"can't copy to file/directory on local system  - file left in PUBDIR/user/file"
79 };
80 
81 
82 #define XUUCP 'X'	/* execute uucp (string) */
83 #define SLTPTCL 'P'	/* select protocol  (string)  */
84 #define USEPTCL 'U'	/* use protocol (character) */
85 #define RCVFILE 'R'	/* receive file (string) */
86 #define SNDFILE 'S'	/* send file (string) */
87 #define RQSTCMPT 'C'	/* request complete (string - yes | no) */
88 #define HUP     'H'	/* ready to hangup (string - yes | no) */
89 #define RESET	'X'	/* reset line modes */
90 
91 #define W_TYPE		wrkvec[0]
92 #define W_FILE1		wrkvec[1]
93 #define W_FILE2		wrkvec[2]
94 #define W_USER		wrkvec[3]
95 #define W_OPTNS		wrkvec[4]
96 #define W_DFILE		wrkvec[5]
97 #define W_MODE		wrkvec[6]
98 #define W_NUSER		wrkvec[7]
99 
100 #define	XFRRATE	35000L
101 #define RMESG(m, s, n) if (rmesg(m, s, n) != 0) {(*Turnoff)(); return FAIL;} else
102 #define RAMESG(s, n) if (rmesg('\0', s, n) != 0) {(*Turnoff)(); return FAIL;} else
103 #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return FAIL;} else
104 
105 char Wfile[MAXFULLNAME] = {'\0'};
106 char Dfile[MAXFULLNAME];
107 
108 /*
109  * To avoid a huge backlog of X. files, start uuxqt every so often.
110  */
111 static int nXfiles = 0;	/* number of X files since last uuxqt start */
112 static char send_or_receive;
113 struct stat stbuf;
114 
115 /*
116  *	cntrl  -  this routine will execute the conversation
117  *	between the two machines after both programs are
118  *	running.
119  *
120  *	return codes
121  *		SUCCESS - ok
122  *		FAIL - failed
123  */
124 
125 cntrl(role, wkpre)
126 int role;
127 char *wkpre;
128 {
129 	char msg[BUFSIZ], rqstr[BUFSIZ];
130 	register FILE *fp;
131 	int filemode;
132 	char filename[MAXFULLNAME], wrktype, *wrkvec[20];
133 	extern (*Rdmsg)(), (*Wrmsg)();
134 	extern char *index(), *lastpart();
135 	int status = 1;
136 	register int i, narg;
137 	int mailopt, ntfyopt;
138 	int ret;
139 	static int pnum, tmpnum = 0;
140 	extern int ReverseRole;
141 
142 	pnum = getpid();
143 	Wfile[0] = '\0';
144 	willturn = turntime > 0;
145 remaster:
146 #ifdef USG
147 	time(&LastTurned.time);
148 	LastTurned.millitm = 0;
149 #else !USG
150 	ftime(&LastTurned);
151 #endif !USG
152 	send_or_receive = RESET;
153 	HaveSentHup = 0;
154 top:
155 	for (i = 0; i < sizeof wrkvec / sizeof wrkvec[0]; i++)
156 		wrkvec[i] = 0;
157 	DEBUG(4, "*** TOP ***  -  role=%s\n", role ? "MASTER" : "SLAVE");
158 	setproctitle("%s: %s", Rmtname, role ? "MASTER" : "SLAVE");
159 	setupline(RESET);
160 	if (Now.time > (LastCheckedNoLogin.time+60)) {
161 		LastCheckedNoLogin = Now;
162 		if (access(NOLOGIN, 0) == 0) {
163 			logent(NOLOGIN, "UUCICO SHUTDOWN");
164 			if (Debug > 4)
165 				logent("DEBUGGING", "continuing anyway");
166 			else {
167 				WMESG(HUP, YES);
168 				RMESG(HUP, msg, 1);
169 				goto process;
170 			}
171 		}
172 	}
173 	if (role == MASTER) {
174 		/* get work */
175 		if (ReverseRole || (narg = gtwvec(Wfile, Spool, wkpre, wrkvec)) == 0) {
176 			ReverseRole = 0;
177 			WMESG(HUP, "");
178 			RMESG(HUP, msg, 1);
179 			goto process;
180 		}
181 		wrktype = W_TYPE[0];
182 
183 		msg[0] = '\0';
184 		for (i = 1; i < narg; i++) {
185 			strcat(msg, " ");
186 			strcat(msg, wrkvec[i]);
187 		}
188 
189 		if (wrktype == XUUCP) {
190 			sprintf(rqstr, "X %s", msg);
191 			logent(rqstr, "REQUEST");
192 			goto sendmsg;
193 		}
194 		mailopt = index(W_OPTNS, 'm') != NULL;
195 		ntfyopt = index(W_OPTNS, 'n') != NULL;
196 
197 		if (narg < 5 || W_TYPE[1] != '\0') {
198 			char *bnp;
199 			bnp = rindex(Wfile, '/');
200 			sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
201 			xmv(Wfile, rqstr);
202 			syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile,
203 				narg);
204 			Wfile[0] = '\0';
205 			goto top;
206 		}
207 		sprintf(User, "%.9s", W_USER);
208 		sprintf(rqstr, "(%s %s %s %s)", W_TYPE, W_FILE1,
209 		  W_FILE2, W_USER);
210 		logent(rqstr, "REQUEST");
211 		if (wrktype == SNDFILE ) {
212 			strcpy(filename, W_FILE1);
213 			i = expfile(filename);
214 			DEBUG(4, "expfile type - %d, ", i);
215 			if (i != 0 && chkpth(User, "", filename))
216 				goto e_access;
217 			strcpy(Dfile, W_DFILE);
218 			fp = NULL;
219 			if (index(W_OPTNS, 'c') == NULL) {
220 				fp = fopen(subfile(Dfile), "r");
221 				if (fp != NULL)
222 					i = 0;
223 			}
224 			if (fp == NULL &&
225 			   (fp = fopen(subfile(filename), "r")) == NULL) {
226 				/*  can not read data file  */
227 				logent("CAN'T READ DATA", _FAILED);
228 				TransferSucceeded = 1; /* else will keep sending */
229 				USRF(USR_LOCACC);
230 				unlinkdf(Dfile);
231 				lnotify(User, filename, "can't access");
232 				goto top;
233 			}
234 			/* if file exists but is not generally readable... */
235 			if (i != 0 && fstat(fileno(fp), &stbuf) == 0
236 			&&  (stbuf.st_mode & ANYREAD) == 0) {
237 		e_access:;
238 				/*  access denied  */
239 				if (fp != NULL) {
240 					fclose(fp);
241 					fp = NULL;
242 				}
243 				TransferSucceeded = 1; /* else will keep sending */
244 				logent("DENIED", "ACCESS");
245 				USRF(USR_LOCACC);
246 				unlinkdf(W_DFILE);
247 				lnotify(User, filename, "access denied");
248 				goto top;
249 			}
250 
251 			setupline(SNDFILE);
252 		}
253 
254 		if (wrktype == RCVFILE) {
255 			strcpy(filename, W_FILE2);
256 			expfile(filename);
257 			if (chkpth(User, "", filename)
258 			 || chkperm(filename, index(W_OPTNS, 'd'))) {
259 				/*  access denied  */
260 				logent("DENIED", "ACCESS");
261 				TransferSucceeded = 1; /* else will keep trying */
262 				USRF(USR_LOCACC);
263 				lnotify(User, filename, "access denied");
264 				goto top;
265 			}
266 			sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
267 			if ((fp = fopen(subfile(Dfile), "w")) == NULL) {
268 				/*  can not create temp  */
269 				logent("CAN'T CREATE TM", _FAILED);
270 				USRF(USR_LNOTMP);
271 				unlinkdf(Dfile);
272 				goto top;
273 			}
274 			setupline(RCVFILE);
275 		}
276 sendmsg:
277 		DEBUG(4, "wrktype - %c\n", wrktype);
278 		WMESG(wrktype, msg);
279 		RMESG(wrktype, msg, 1);
280 		goto process;
281 	}
282 
283 	/* role is slave */
284 	RAMESG(msg, 1);
285 	if (willturn < 0)
286 		willturn = msg[0] == HUP;
287 
288 process:
289 	DEBUG(4, "PROCESS: msg - %s\n", msg);
290 	switch (msg[0]) {
291 
292 	case RQSTCMPT:
293 		DEBUG(4, "RQSTCMPT:\n", CNULL);
294 		if (msg[1] == 'N') {
295 			i = atoi(&msg[2]);
296 			if (i<0 || i>EM_MAX)
297 				i = 0;
298 			USRF( 1 << i );
299 			logent(Em_msg[i], "REQUEST FAILED");
300 			TransferSucceeded = 1; /* He had his chance */
301 		}
302 		if (msg[1] == 'Y') {
303 			USRF(USR_COK);
304 			TransferSucceeded = 1;
305 		}
306 		if (role == MASTER)
307 			notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
308 
309 		if (msg[2] == 'M' && role == MASTER) {
310 			extern int Nfiles;
311 			WMESG(HUP, "");
312 			RMESG(HUP, msg, 1);
313 			logent(Rmtname, "TURNAROUND");
314 #ifdef USG
315 				time(&LastTurned.time);
316 				LastTurned.millitm = 0;
317 #else !USG
318 				ftime(&LastTurned);
319 #endif !USG
320 			Nfiles = 0; /* force rescan of queue for work */
321 			goto process;
322 		}
323 		goto top;
324 
325 	case HUP:
326 		DEBUG(4, "HUP:\n", CNULL);
327 		HaveSentHup = 1;
328 		if (msg[1] == 'Y') {
329 			if (role == MASTER)
330 				WMESG(HUP, YES);
331 			(*Turnoff)();
332 			Rdmsg = Imsg;
333 			Wrmsg = Omsg;
334 			return SUCCESS;
335 		}
336 
337 		if (msg[1] == 'N') {
338 			if (role != MASTER) {
339 				syslog(LOG_ERR, "Wrong Role - HUP");
340 				cleanup(FAIL);
341 			}
342 			role = SLAVE;
343 			goto remaster;
344 		}
345 
346 		/* get work */
347 		if (!iswrk(Wfile, "chk", Spool, wkpre)) {
348 			WMESG(HUP, YES);
349 			RMESG(HUP, msg, 1);
350 			goto process;
351 		}
352 
353 		WMESG(HUP, NO);
354 		/*
355 		 * want to create an orphan uuxqt,
356 		 * so a double-fork is needed.
357 		 */
358 		if (fork() == 0) {
359 			xuuxqt();
360 			_exit(0);
361 		}
362 		wait((int *)0);
363 		role = MASTER;
364 		goto remaster;
365 
366 	case XUUCP:
367 		if (role == MASTER) {
368 			goto top;
369 		}
370 
371 		/*  slave part  */
372 		i = getargs(msg, wrkvec, 20);
373 		strcpy(filename, W_FILE1);
374 		if (index(filename, ';') != NULL || index(W_FILE2, ';') != NULL
375 		    || i < 3) {
376 			WMESG(XUUCP, NO);
377 			goto top;
378 		}
379 		expfile(filename);
380 		if (chkpth("", Rmtname, filename)) {
381 			WMESG(XUUCP, NO);
382 			logent("XUUCP DENIED", filename);
383 				USRF(USR_XUUCP);
384 			goto top;
385 		}
386 		sprintf(rqstr, "%s %s", filename, W_FILE2);
387 		xuucp(rqstr);
388 		WMESG(XUUCP, YES);
389 		goto top;
390 
391 	case SNDFILE:
392 		/*  MASTER section of SNDFILE  */
393 
394 		DEBUG(4, "%s\n", "SNDFILE:");
395 		if (msg[1] == 'N') {
396 			i = atoi(&msg[2]);
397 			if (i < 0 || i > EM_MAX)
398 				i = 0;
399 			logent(Em_msg[i], "REQUEST FAILED");
400 			USRF( 1 << i );
401 			fclose(fp);
402 			fp = NULL;
403 			/* dont send him files he can't save */
404 			if (strcmp(&msg[1], EM_NOTMP) == 0) {
405 				WMESG(HUP, "");
406 				RMESG(HUP, msg, 1);
407 				goto process;
408 			}
409 			notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
410 			if (role != MASTER) {
411 				syslog(LOG_ERR, "Wrong Role - SN");
412 				cleanup(FAIL);
413 			}
414 			unlinkdf(W_DFILE);
415 			goto top;
416 		}
417 
418 		if (msg[1] == 'Y') {
419 			/* send file */
420 			if (role != MASTER) {
421 				syslog(LOG_ERR, "Wrong Role - SY");
422 				cleanup(FAIL);
423 			}
424 			if (fstat(fileno(fp), &stbuf) < 0) {
425 				syslog(LOG_ERR, "stat(%s) failed: %m",filename);
426 				cleanup(FAIL);
427 			}
428 			i = 1 + (int)(stbuf.st_size / XFRRATE);
429 			if (send_or_receive != SNDFILE) {
430 				send_or_receive = SNDFILE;
431 				systat(Rmtname, SS_INPROGRESS, "SENDING");
432 			}
433 			ret = (*Wrdata)(fp, Ofn);
434 			fclose(fp);
435 			fp = NULL;
436 			if (ret != SUCCESS) {
437 				(*Turnoff)();
438 				USRF(USR_CFAIL);
439 				return FAIL;
440 			}
441 			RMESG(RQSTCMPT, msg, i);
442 			unlinkdf(W_DFILE);
443 			goto process;
444 		}
445 
446 		/*  SLAVE section of SNDFILE  */
447 		if (role != SLAVE) {
448 			syslog(LOG_ERR, "Wrong Role - SLAVE");
449 			cleanup(FAIL);
450 		}
451 
452 		/* request to receive file */
453 		/* check permissions */
454 		i = getargs(msg, wrkvec, 20);
455 		if (i < 5) {
456 			char *bnp;
457 			bnp = rindex(Wfile, '/');
458 			sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
459 			xmv(Wfile, rqstr);
460 			syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile, i);
461 			Wfile[0] = '\0';
462 			goto top;
463 		}
464 		sprintf(rqstr, "(%s %s %s %s)", W_TYPE, W_FILE1, W_FILE2,
465 			W_USER);
466 		logent(rqstr, "REQUESTED");
467 		DEBUG(4, "msg - %s\n", msg);
468 		strcpy(filename, W_FILE2);
469 		/* Run uuxqt occasionally */
470 		if (filename[0] == XQTPRE) {
471 			if (++nXfiles > 10) {
472 				nXfiles = 0;
473 				/*
474 				 * want to create an orphan uuxqt,
475 				 * so a double-fork is needed.
476 				 */
477 				if (fork() == 0) {
478 					xuuxqt();
479 					_exit(0);
480 				}
481 				wait((int *)0);
482 			}
483 		}
484 		/* expand filename, i is set to 0 if this is
485 		 * is a vanilla spool file, so no stat(II)s are needed */
486 		i = expfile(filename);
487 		DEBUG(4, "expfile type - %d\n", i);
488 		if (i != 0) {
489 			if (chkpth("", Rmtname, filename)
490 			 || chkperm(filename, index(W_OPTNS, 'd'))) {
491 				WMESG(SNDFILE, EM_RMTACC);
492 				logent("DENIED", "PERMISSION");
493 				goto top;
494 			}
495 			if (isdir(filename)) {
496 				strcat(filename, "/");
497 				strcat(filename, lastpart(W_FILE1));
498 			}
499 		}
500 		sprintf(User, "%.9s", W_USER);
501 
502 		DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
503 		/* speed things up by OKing file before
504 		 * creating TM file.  If the TM file cannot be created,
505 		 * then the conversation bombs, but that seems reasonable,
506 		 * as there are probably serious problems then.
507 		 */
508 		WMESG(SNDFILE, YES);
509 		sprintf(Dfile, "%s/TM.%05d.%03d", Spool, pnum, tmpnum++);
510 		if((fp = fopen(subfile(Dfile), "w")) == NULL) {
511 /*			WMESG(SNDFILE, EM_NOTMP);*/
512 			logent("CAN'T OPEN", "TM FILE");
513 			unlinkdf(Dfile);
514 			(*Turnoff)();
515 			return FAIL;
516 		}
517 
518 		if (send_or_receive != RCVFILE) {
519 			send_or_receive = RCVFILE;
520 			systat(Rmtname, SS_INPROGRESS, "RECEIVING");
521 		}
522 		ret = (*Rddata)(Ifn, fp);
523 		fflush(fp);
524 		if (ferror(fp) || fclose(fp))
525 			ret = FAIL;
526 
527 		if (ret != SUCCESS) {
528 			(void) unlinkdf(Dfile);
529 			(*Turnoff)();
530 			return FAIL;
531 		}
532 		/* copy to user directory */
533 		ntfyopt = index(W_OPTNS, 'n') != NULL;
534 		status = xmv(Dfile, filename);
535 
536 		if (willturn && Now.time > (LastTurned.time+turntime)
537 			&& iswrk(Wfile, "chk", Spool, wkpre)) {
538 				WMESG(RQSTCMPT, status ? EM_RMTCP : "YM");
539 				willturn = -1;
540 		} else
541 			WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
542 		if (i == 0)
543 			;	/* vanilla file, nothing to do */
544 		else if (status == 0) {
545 			if (W_MODE == 0 || sscanf(W_MODE, "%o", &filemode) != 1)
546 				filemode = BASEMODE;
547 			chmod(subfile(filename), (filemode|BASEMODE)&0777);
548 			arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
549 		} else {
550 			logent(_FAILED, "COPY");
551 			status = putinpub(filename, Dfile, W_USER);
552 			DEBUG(4, "->PUBDIR %d\n", status);
553 			if (status == 0)
554 				arrived(ntfyopt, filename, W_NUSER, Rmtname, User);
555 		}
556 
557 		goto top;
558 
559 	case RCVFILE:
560 		/*  MASTER section of RCVFILE  */
561 
562 		DEBUG(4, "%s\n", "RCVFILE:");
563 		if (msg[1] == 'N') {
564 			i = atoi(&msg[2]);
565 			if (i < 0 || i > EM_MAX)
566 				i = 0;
567 			logent(Em_msg[i], "REQUEST FAILED");
568 			USRF( 1 << i );
569 			fclose(fp);
570 			fp = NULL;
571 			notify(mailopt, W_USER, W_FILE1, Rmtname, &msg[1]);
572 			if (role != MASTER) {
573 				syslog(LOG_ERR, "Wrong Role - RN");
574 				cleanup(FAIL);
575 			}
576 			unlinkdf(Dfile);
577 			goto top;
578 		}
579 
580 		if (msg[1] == 'Y') {
581 			/* receive file */
582 			if (role != MASTER) {
583 				syslog(LOG_ERR, "Wrong Role - RY");
584 				cleanup(FAIL);
585 			}
586 			if (send_or_receive != RCVFILE) {
587 				send_or_receive = RCVFILE;
588 				systat(Rmtname, SS_INPROGRESS, "RECEIVING");
589 			}
590 			ret = (*Rddata)(Ifn, fp);
591 			fflush(fp);
592 			if (ferror(fp) || fclose(fp))
593 				ret = FAIL;
594 			if (ret != SUCCESS) {
595 				unlinkdf(Dfile);
596 				(*Turnoff)();
597 				USRF(USR_CFAIL);
598 				return FAIL;
599 			}
600 			/* copy to user directory */
601 			if (isdir(filename)) {
602 				strcat(filename, "/");
603 				strcat(filename, lastpart(W_FILE1));
604 			}
605 			status = xmv(Dfile, filename);
606 			WMESG(RQSTCMPT, status ? EM_RMTCP : YES);
607 			notify(mailopt, W_USER, filename, Rmtname,
608 				status ? EM_LOCCP : YES);
609 			if (status == 0) {
610 				sscanf(&msg[2], "%o", &filemode);
611 				if (filemode <= 0)
612 					filemode = BASEMODE;
613 				chmod(subfile(filename), (filemode|BASEMODE)&0777);
614 				USRF(USR_COK);
615 			} else {
616 				logent(_FAILED, "COPY");
617 				putinpub(filename, Dfile, W_USER);
618 				USRF(USR_LOCCP);
619 			}
620 			if (msg[strlen(msg)-1] == 'M') {
621 				extern int Nfiles;
622 				WMESG(HUP, "");
623 				RMESG(HUP, msg, 1);
624 				logent(Rmtname, "TURNAROUND");
625 #ifdef USG
626 				time(&LastTurned.time);
627 				LastTurned.millitm = 0;
628 #else !USG
629 				ftime(&LastTurned);
630 #endif !USG
631 				Nfiles = 0; /* force rescan of queue for work */
632 				goto process;
633 			}
634 			goto top;
635 		}
636 
637 		/*  SLAVE section of RCVFILE  */
638 		if (role != SLAVE) {
639 			syslog(LOG_ERR, "Wrong Role - SLAVE RCV");
640 			cleanup(FAIL);
641 		}
642 
643 		/* request to send file */
644 		sprintf(rqstr,"(%s)", msg);
645 		logent(rqstr, "REQUESTED");
646 
647 		/* check permissions */
648 		i = getargs(msg, wrkvec, 20);
649 		if (i < 4) {
650 			char *bnp;
651 			bnp = rindex(Wfile, '/');
652 			sprintf(rqstr, "%s/%s", CORRUPT, bnp ? bnp + 1 : Wfile);
653 			xmv(Wfile, rqstr);
654 			syslog(LOG_WARNING, "%s CORRUPTED: %d args", Wfile, i);
655 			Wfile[0] = '\0';
656 			goto top;
657 		}
658 		DEBUG(4, "msg - %s\n", msg);
659 		DEBUG(4, "W_FILE1 - %s\n", W_FILE1);
660 		strcpy(filename, W_FILE1);
661 		expfile(filename);
662 		if (isdir(filename)) {
663 			strcat(filename, "/");
664 			strcat(filename, lastpart(W_FILE2));
665 		}
666 		sprintf(User, "%.9s", W_USER);
667 		if (chkpth("", Rmtname, filename) || anyread(filename)) {
668 			WMESG(RCVFILE, EM_RMTACC);
669 			logent("DENIED", "PERMISSION");
670 			goto top;
671 		}
672 		DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname);
673 
674 		if ((fp = fopen(subfile(filename), "r")) == NULL) {
675 			WMESG(RCVFILE, EM_RMTACC);
676 			logent("CAN'T OPEN", "DENIED");
677 			goto top;
678 		}
679 
680 		/*  ok to send file */
681 		if (fstat(fileno(fp), &stbuf) < 0) {
682 			syslog(LOG_ERR, "stat(%s) failed: %m", filename);
683 			cleanup(FAIL);
684 		}
685 
686 		i = 1 + (int)(stbuf.st_size / XFRRATE);
687 		if (willturn && Now.time > (LastTurned.time+turntime)
688 			&& iswrk(Wfile, "chk", Spool, wkpre)) {
689 				willturn = -1;
690 		}
691 		sprintf(msg, "%s %o%s", YES, (int)stbuf.st_mode & 0777,
692 			willturn < 0 ? " M" : "");
693 		WMESG(RCVFILE, msg);
694 		if (send_or_receive != SNDFILE) {
695 			send_or_receive = SNDFILE;
696 			systat(Rmtname, SS_INPROGRESS, "SENDING");
697 		}
698 		ret = (*Wrdata)(fp, Ofn);
699 		fclose(fp);
700 		if (ret != SUCCESS) {
701 			(*Turnoff)();
702 			return FAIL;
703 		}
704 		RMESG(RQSTCMPT, msg, i);
705 		goto process;
706 	}
707 	(*Turnoff)();
708 	return FAIL;
709 }
710 
711 
712 /*
713  *	read message 'c'. try 'n' times
714  *
715  *	return code:  SUCCESS  |  FAIL
716  */
717 rmesg(c, msg, n)
718 register char *msg, c;
719 register int n;
720 {
721 	char str[MAXFULLNAME];
722 
723 	DEBUG(4, "rmesg - '%c' ", c);
724 	while ((*Rdmsg)(msg, Ifn) != SUCCESS) {
725 		if (--n > 0) {
726 			sprintf(str, "%d", n);
727 			logent(str, "PATIENCE");
728 			continue;
729 		}
730 		DEBUG(4, "got FAIL\n", CNULL);
731 		if (c != '\0')
732 			sprintf(str, "expected '%c' got FAIL (%d)", c, errno);
733 		else
734 			sprintf(str, "expected ANY got FAIL (%d)", errno);
735 		logent(str, "BAD READ");
736 		return FAIL;
737 	}
738 	if (c != '\0' && msg[0] != c) {
739 		DEBUG(4, "got %s\n", msg);
740 		sprintf(str, "expected '%c' got %s", c, msg);
741 		logent(str, "BAD READ");
742 		return FAIL;
743 	}
744 	DEBUG(4, "got %s\n", msg);
745 	return SUCCESS;
746 }
747 
748 
749 /*
750  *	write a message (type m)
751  *
752  *	return codes: SUCCESS - ok | FAIL - ng
753  */
754 wmesg(m, s)
755 register char *s, m;
756 {
757 	DEBUG(4, "wmesg '%c' ", m);
758 	DEBUG(4, "%s\n", s);
759 	return (*Wrmsg)(m, s, Ofn);
760 }
761 
762 /*
763  *	mail results of command
764  *
765  *	return codes:  none
766  */
767 notify(mailopt, user, file, sys, msgcode)
768 char *user, *file, *sys, *msgcode;
769 {
770 	char str[BUFSIZ];
771 	int i;
772 	char *msg;
773 
774 	if (!mailopt && *msgcode == 'Y')
775 		return;
776 	if (*msgcode == 'Y')
777 		msg = "copy succeeded";
778 	else {
779 		i = atoi(msgcode + 1);
780 		if (i < 1 || i > EM_MAX)
781 			i = 0;
782 		msg = Em_msg[i];
783 	}
784 	sprintf(str, "file %s!%s -- %s\n",
785 		sys,file, msg);
786 	mailst(user, str, CNULL);
787 	return;
788 }
789 
790 /*
791  *	local notify
792  *
793  *	return code - none
794  */
795 lnotify(user, file, mesg)
796 char *user, *file, *mesg;
797 {
798 	char mbuf[200];
799 	sprintf(mbuf, "file %s!%s -- %s\n", Myname, file, mesg);
800 	mailst(user, mbuf, CNULL);
801 	return;
802 }
803 
804 char UsingProtocol;
805 
806 /*
807  *	converse with the remote machine, agree upon a protocol (if possible)
808  *	and start the protocol.
809  *
810  *	return codes:
811  *		SUCCESS - successful protocol selection
812  *		FAIL - can't find common or open failed
813  */
814 startup(role)
815 int role;
816 {
817 	extern (*Rdmsg)(), (*Wrmsg)();
818 	extern char *blptcl(), fptcl();
819 	char msg[BUFSIZ], str[MAXFULLNAME];
820 
821 	Rdmsg = Imsg;
822 	Wrmsg = Omsg;
823 	if (role == MASTER) {
824 		RMESG(SLTPTCL, msg, 1);
825 		if ((str[0] = fptcl(&msg[1])) == NULL) {
826 			/* no protocol match */
827 			WMESG(USEPTCL, NO);
828 			return FAIL;
829 		}
830 		str[1] = '\0';
831 		WMESG(USEPTCL, str);
832 		if (stptcl(str) != 0)
833 			return FAIL;
834 		DEBUG(4, "protocol %s\n", str);
835 		UsingProtocol = str[0];
836 		return SUCCESS;
837 	}
838 	else {
839 		WMESG(SLTPTCL, blptcl(str));
840 		RMESG(USEPTCL, msg, 1);
841 		if (msg[1] == 'N') {
842 			return FAIL;
843 		}
844 
845 		if (stptcl(&msg[1]) != 0)
846 			return FAIL;
847 		DEBUG(4, "Protocol %s\n", msg);
848 		UsingProtocol = msg[1];
849 		return SUCCESS;
850 	}
851 }
852 
853 /*
854  *	choose a protocol from the input string (str) and return the it
855  *
856  *	return codes:
857  *		'\0'  -  no acceptable protocol
858  *		any character  -  the chosen protocol
859  */
860 char
861 fptcl(str)
862 register char *str;
863 {
864 	register struct Proto *p;
865 	extern char LineType[];
866 
867 	for (p = Ptbl; p->P_id != '\0'; p++) {
868 #ifdef TCPIP
869 		/* Only use 't' on TCP/IP */
870 		if (p->P_id == 't' && strcmp("TCP", LineType))
871 			continue;
872 #endif TCPIP
873 #ifdef PAD
874 		/* only use 'f' protocol on PAD */
875 		if (p->P_id == 'f' && strcmp("PAD", LineType))
876 			continue;
877 #endif PAD
878 		if (index(str, p->P_id) != NULL) {
879 			return p->P_id;
880 		}
881 	}
882 
883 	return '\0';
884 }
885 
886 /*
887  *	build a string of the letters of the available protocols
888  */
889 char *
890 blptcl(str)
891 register char *str;
892 {
893 	register struct Proto *p;
894 	register char *s;
895 
896 	for (p = Ptbl, s = str; (*s++ = p->P_id) != '\0'; p++)
897 		;
898 	*s = '\0';
899 	return str;
900 }
901 
902 /*
903  *	this routine will set up the six routines
904  *	(Rdmsg, Wrmsg, Rddata, Wrdata, Turnon, Turnoff) for the
905  *	desired protocol.
906  *
907  *	return codes:
908  *		SUCCESS - ok
909  *		FAIL - no find or failed to open
910  *
911  */
912 stptcl(c)
913 register char *c;
914 {
915 	register struct Proto *p;
916 
917 	for (p = Ptbl; p->P_id != '\0'; p++) {
918 		if (*c == p->P_id) {
919 			/* found protocol - set routines */
920 			Rdmsg = p->P_rdmsg;
921 			Wrmsg = p->P_wrmsg;
922 			Rddata = p->P_rddata;
923 			Wrdata = p->P_wrdata;
924 			Turnon = p->P_turnon;
925 			Turnoff = p->P_turnoff;
926 			if ((*Turnon)() != SUCCESS)
927 				return FAIL;
928 			DEBUG(4, "Proto started %c\n", *c);
929 			return SUCCESS;
930 		}
931 	}
932 	DEBUG(4, "Proto start-fail %c\n", *c);
933 	return FAIL;
934 }
935 
936 /*
937  *	put file in public place. if successful, filename is modified
938  *
939  *	return code  SUCCESS | FAIL
940  */
941 
942 putinpub(file, tmp, user)
943 register char *file, *tmp, *user;
944 {
945 	char fullname[MAXFULLNAME];
946 	char *lastpart();
947 	int status;
948 
949 	sprintf(fullname, "%s/%s/", PUBDIR, user);
950 	if (mkdirs(fullname) != 0) {
951 		/* can not make directories */
952 		DEBUG(1, "Cannot mkdirs(%s)\n", fullname);
953 		return FAIL;
954 	}
955 	strcat(fullname, lastpart(file));
956 	status = xmv(tmp, fullname);
957 	if (status == 0) {
958 		strcpy(file, fullname);
959 		chmod(subfile(fullname), BASEMODE);
960 	}
961 	return status;
962 }
963 
964 /*
965  *	unlink D. file
966  *
967  *	return code - none
968  */
969 
970 unlinkdf(file)
971 register char *file;
972 {
973 	if (strlen(file) > 6)
974 		unlink(subfile(file));
975 	return;
976 }
977 
978 /*
979  *	notify receiver of arrived file
980  *
981  *	return code - none
982  */
983 arrived(opt, file, nuser, rmtsys, rmtuser)
984 char *file, *nuser, *rmtsys, *rmtuser;
985 {
986 	char mbuf[200];
987 
988 	if (!opt)
989 		return;
990 	sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser);
991 	mailst(nuser, mbuf, CNULL);
992 	return;
993 }
994 
995 nullf()
996 {
997 	return SUCCESS;
998 }
999