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