xref: /titanic_44/usr/src/cmd/bnu/uucleanup.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1994 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /*
34  *	uucleanup - This is a program based on the heuristics
35  *	for cleaning up and doing something
36  *	useful with old files left in the uucp queues.
37  *	It also will send warning messags to users where requests are not
38  *	going out due to failure to contact the remote system.
39  *
40  *	This program knows a lot about the construction and
41  *	contents of the C., D. and X. files.  In addition, it
42  *	thinks it knows what mail and netnews data files look like.
43  *
44  *	At present, this is what is done:
45  *	For WARNING messages:
46  *	C. files of age given by -W option are read, looking for
47  *		either user files to be sent or received, or
48  *		mail to be sent.  (Other remote execution that
49  *		does not involve sending user files is not checked
50  *		for now.)  In either of the cases, the user is
51  *		informed by mail that the request is not being
52  *		processed due to lack of communications with the remote
53  *		system, and the request will be deleted in the future
54  *		if it the condition remains for several more days.
55  *
56  *	For DELETIONS:
57  *	C. files - if they reference only D. files, the C. is
58  *		merely deleted, because the D. files are usually
59  *		mail or news, and the later D. processing will
60  *		take care of them.
61  *		- if they reference files from the file system,
62  *		a message is constructed that will contain a
63  *		lines like
64  *		   We can't contact the remote.
65  *
66  *		   local!file -> remote!otherfile
67  *
68  *		   can't be executed.
69  *	X. files - merely deleted at present - D.s will be taken
70  *		care of later. Besides, some of the D.s are
71  *		missing or else the X. wouldn't be left around.
72  *	D. files - mail type data is sent to a local person if that
73  *		is where it originated.  If not, it is returned to the
74  *		sender -- assumed to be from the first From line.  If
75  *		a sender can't be determing, the file is merely deleted.
76  *		- rnews: if locally generated, just delete.  If remote,
77  *		the X. got lost, so execute rnews.
78  *	other files - just delete them.
79  *	.Workspace files over a day old
80  *
81  *	Deletions and executions are logged in
82  *	(CLEANUPLOG)--/var/uucp/.Admin/uucleanup
83 */
84 
85 #include	"uucp.h"
86 
87 #ifdef	V7
88 #define O_RDONLY	0
89 #endif
90 
91 #define USAGE	"[-oDAYS] [-mSTRING] [-Cdays] [-Ddays] [-Wdays] [-Xdays] [-xLEVEL] [-sSYSTEM]"
92 
93 extern int _age();		/* find the age of a file */
94 extern void procdtype(), oprocess(), xprocess(), cprocess();
95 extern void dXprocess(), dNprocess(), dMprocess(), dDprocess(), wprocess();
96 extern int toWho(), sendMail(), execRnews();
97 extern void logit();
98 
99 /* need these dummys to satisy some .o files */
100 void cleanup(){}
101 void systat(){}
102 void logent(){}
103 
104 
105 /* types of D. files */
106 #define D_MAIL	1
107 #define D_NEWS	2
108 #define D_XFILE	3
109 #define D_DATA	4
110 #define FULLNAME(full,dir,file)	(void) sprintf(full, "%s/%s", dir, file);
111 
112 int _Ddays = 7;			/* D. limit */
113 int _Cdays = 7;			/* C. limit */
114 int _Xdays = 2;			/* X. limit */
115 int _Odays = 2;			/* O. limit */
116 int _Wdays = 1;			/* Warning limit for C. files */
117 char _ShortLocal[6];		/* 5 char or less version of local name */
118 
119 char *_Undeliverable[] = {
120 "Subject: Undeliverable Mail\n",
121 "This mail message is undeliverable.\n",
122 "(Probably to or from system '%s')\n",
123 "It was sent to you or by you.\n",
124 "Sorry for the inconvenience.\n",
125 "",
126 };
127 
128 #define CANT1	2	/* first line to fill in */
129 #define CANT2	3	/* second line to fill in */
130 char *_CantContact[] = {
131 "Subject: Job Killed By uucp\n",
132 "We can't contact machine '%s'.\n",
133 " ",	/* uucleanup will fill in variable text here */
134 " ",	/* fill in jobid of killed job */
135 "",
136 };
137 
138 #define WARN1	2
139 #define WARN2	5
140 #define WARN3	6
141 char *_Warning[] = {
142 "Subject: Warning From uucp\n",
143 "We have been unable to contact machine '%s' since you queued your job.\n",
144 " ",	/*  wprocess FILLS IN THIS LINE OF TEXT */
145 "Attempts will continue for a few more days.\n",
146 "",
147 " ",	/*  wprocess FILLS IN THIS LINE WITH:  uucp job id is JOBid. */
148 " ",	/* FILL IN THE -m STRING IF SPECIFIED */
149 "",
150 };
151 
152 main(argc, argv, envp)
153 char *argv[];
154 char **envp;
155 {
156 	DIR *jcdir, *machdir, *spooldir;
157 	char fullname[MAXFULLNAME], statfile[MAXFULLNAME], machname[MAXFULLNAME];
158 	char file1[NAMESIZE+1], file2[NAMESIZE+1], file3[NAMESIZE+1];
159 	char soptName[MAXFULLNAME], lockname[MAXFULLNAME];	/* name from -s option */
160 	int i, value;
161 
162 	soptName[0] = NULLCHAR;
163 	(void) strcpy(Logfile, CLEANUPLOGFILE);
164 	uucpname(Myname);
165 	(void) strncpy(_ShortLocal, Myname, 5);
166 	_ShortLocal[5] = NULLCHAR;
167 	(void) strcpy(Progname, "uucleanup");
168 	while ((i = getopt(argc, argv, "C:D:W:X:m:o:s:x:")) != EOF) {
169 		switch(i){
170 		case 's':	/* for debugging - choose system */
171 			(void) strcpy(soptName, optarg);
172 			break;
173 		case 'x':
174 			Debug = atoi(optarg);
175 			if (Debug <= 0 || Debug >= 10) {
176 				fprintf(stderr,
177 				"WARNING: %s: invalid debug level %s ignored, using level 1\n",
178 					Progname, optarg);
179 				Debug = 1;
180 			}
181 #ifdef SMALL
182 			fprintf(stderr,
183 				"WARNING: uucleanup built with SMALL flag defined -- no debug info available\n");
184 #endif /* SMALL */
185 			break;
186 		case 'm':
187 			_Warning[WARN3] = optarg;
188 			break;
189 		default:
190 			(void) fprintf(stderr, "\tusage: %s %s\n",
191 				Progname, USAGE);
192 			exit(1);
193 
194 		case 'C':
195 		case 'D':
196 		case 'W':
197 		case 'X':
198 		case 'o':
199 			value = atoi(optarg);
200 			if (value < 1) {
201 				fprintf(stderr," Options: CDWXo require value > 0\n");
202 				exit(1);
203 			}
204 			switch(i) {
205 			case 'C':
206 				_Cdays = value;
207 				break;
208 			case 'D':
209 				_Ddays = value;
210 				break;
211 			case 'W':
212 				_Wdays = value;
213 				break;
214 			case 'X':
215 				_Xdays = value;
216 				break;
217 			case 'o':
218 				_Odays = value;
219 				break;
220 			}
221 			break;
222 		}
223 	}
224 
225 	if (argc != optind) {
226 		(void) fprintf(stderr, "\tusage: %s %s\n", Progname, USAGE);
227 		exit(1);
228 	}
229 
230 	DEBUG(5, "Progname (%s): STARTED\n", Progname);
231 	DEBUG(5, "Myname (%s), ", Myname);
232 	DEBUG(5, "_ShortLocal (%s)\n", _ShortLocal);
233 	DEBUG(5, "Days C.(%d), ", _Cdays);
234 	DEBUG(5, "D.(%d), ", _Ddays);
235 	DEBUG(5, "W.(%d), ", _Wdays);
236 	DEBUG(5, "X.(%d), ", _Xdays);
237 	DEBUG(5, "other (%d)\n", _Odays);
238 
239 	cleanworkspace();
240 	if (chdir(SPOOL) != 0) {
241 		(void) fprintf(stderr, "CAN'T CHDIR (%s): errno (%d)\n",
242 			SPOOL, errno);
243 		exit(1);
244 	}
245 	if ((spooldir = opendir(SPOOL)) == NULL) {
246 		(void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n",
247 			SPOOL, errno);
248 		exit(1);
249 	}
250 
251 	while (gdirf(spooldir, file1, SPOOL) == TRUE) {
252 
253 		if (*soptName && !EQUALS(soptName, file1))
254 			continue;
255 
256 		(void) strcpy(Rmtname, file1);
257 		(void) sprintf(machname, "%s/%s", SPOOL, file1);
258 		if ((machdir = opendir(machname)) == NULL) {
259 			(void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n",
260 				machname, errno);
261 			if (*soptName)
262 				break;
263 			else
264 				continue;
265 		}
266 		DEBUG(7, "Directory: (%s) is open\n", file1);
267 		while (gnamef(machdir, file2) == TRUE) {
268 
269 			(void) sprintf(statfile, "%s/%s", machname, file2);
270 			if (DIRECTORY(statfile)) {
271 				(void) sprintf(lockname, "%s.%.*s.%s",
272 					LOCKPRE, SYSNSIZE, file1, file2);
273 				if (cklock(lockname))
274 					continue;
275 				if ((jcdir = opendir(statfile)) == NULL) {
276 					(void) fprintf(stderr,
277 						"CAN'T OPEN (%s): errno (%d)\n",
278 						statfile, errno);
279 					continue;
280 				}
281 
282 				DEBUG(7, "Directory: (%s) is open\n", file2);
283 				while (gnamef(jcdir, file3)) {
284 					DEBUG(9, "file: %s\n", file3);
285 					FULLNAME(fullname, statfile, file3);
286 					DEBUG(9,"Fullname is (%s)\n", fullname);
287 					if (EQUALSN(file3, "C.", 2)) {
288 						if (_age(fullname) >= _Cdays)
289 							cprocess(fullname);
290 						else if(_age(fullname) >= _Wdays)
291 							wprocess(statfile, file3);
292 					}
293 					else if (EQUALSN(file3, "D.", 2)) {
294 						if (_age(fullname) >= _Ddays)
295 							procdtype(statfile, file3);
296 					}
297 					else if (_age(fullname) >= _Odays)
298 						oprocess(fullname);
299 				}
300 				closedir(jcdir);
301 				continue;
302 			}
303 			DEBUG(9, "file: %s\n", file2);
304 			DEBUG(9, "Fullname is (%s)\n", statfile);
305 			if (EQUALSN(file2, "X.", 2)) {
306 				if (_age(statfile) >= _Xdays)
307 					xprocess(statfile);
308 			}
309 			else if (EQUALSN(file2, "D.", 2)) {
310 				if (_age(statfile) >= _Ddays)
311 					procdtype(machname, file2);
312 			}
313 			else if (_age(statfile) >= _Odays)
314 				oprocess(statfile);
315 		}
316 		closedir(machdir);
317 	}
318 	closedir(spooldir);
319 	exit(0);
320 
321 	/* NOTREACHED */
322 }
323 
324 /* procdtype - select the type of processing that a D. file should receive */
325 
326 void
327 procdtype(dir, file)
328 char *dir, *file;
329 {
330 
331 	char fullname[MAXFULLNAME];
332 
333 	FULLNAME(fullname, dir, file);
334 
335 	switch(dType(fullname)) {
336 	case D_DATA:
337 		dDprocess(fullname);
338 		break;
339 	case D_MAIL:
340 		dMprocess(dir, file);
341 		break;
342 	case D_NEWS:
343 		dNprocess(dir, file);
344 		break;
345 	case D_XFILE:
346 		dXprocess(fullname);
347 		break;
348 	default:
349 		break;
350 	}
351 	return;
352 }
353 
354 /* xprocess - X. file processing -- just remove the X. for now */
355 
356 void
357 xprocess(fullname)
358 char *fullname;
359 {
360 	char text[BUFSIZ];
361 
362 	DEBUG(5, "xprocess(%s), ", fullname);
363 	DEBUG(5, "unlink(%s)\n", fullname);
364 	(void) sprintf(text, "xprocess: unlink(%s)", fullname);
365 	errno = 0;
366 	(void) unlink(fullname);
367 	logit(text, errno);
368 	return;
369 }
370 
371 /*
372  * cprocess - Process old C. files
373  *
374  */
375 
376 #define CMFMT  "\n\t%s!%s -> %s!%s   (Date %2.2d/%2.2d)\n\nCan't be executed."
377 #define XFMT  "\n\t%s!%s  (Date %2.2d/%2.2d)\n"
378 #define XMFMT  "\n\tmail %s!%s   (Date %2.2d/%2.2d)\n"
379 #define WFMT  "\n\t%s!%s -> %s!%s   (Date %2.2d/%2.2d)\n"
380 void
381 cprocess(fullname)
382 char *fullname;
383 {
384 	struct stat s;
385 	register struct tm *tp;
386 	char buf[BUFSIZ], user[9];
387 	char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256];
388 	char text[BUFSIZ], text1[BUFSIZ], text2[BUFSIZ];
389 	FILE *fp;
390 	int ret;
391 
392 	DEBUG(5, "cprocess(%s)\n", fullname);
393 
394 
395 	fp = fopen(fullname, "r");
396 	if (fp == NULL) {
397 		DEBUG(5, "Can't open file (%s), ", fullname);
398 		DEBUG(5, "errno=%d -- skip it!\n", errno);
399 		return;
400 	}
401 	if (fstat(fileno(fp), &s) != 0) {
402 	    /* can't happen; _age() did stat of this file and file is opened */
403 	    (void) fclose(fp);
404 	    return;
405 	}
406 	tp = localtime(&s.st_mtime);
407 
408 	if (s.st_size == 0) { /* dummy C. for polling */
409 		DEBUG(5, "dummy C. -- unlink(%s)\n", fullname);
410 		(void) sprintf(text, "dDprocess: dummy C. unlinked(%s)",
411 			fullname);
412 		errno = 0;
413 		(void) unlink(fullname);
414 		logit(text, errno);
415 		(void) fclose(fp);
416 		return;
417 	}
418 
419 	/* Read the C. file and process it */
420 	while (fgets(buf, BUFSIZ, fp) != NULL) {
421 		buf[strlen(buf)-1] = NULLCHAR; /* remove \n */
422 		if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2,
423 			user, opt, file3) <5) {
424 			(void) sprintf(text, "cprocess: Bad C. %s, unlink(%s)",
425 				buf, fullname);
426 			break;
427 		}
428 
429 		*text = NULLCHAR;
430 		ret = 0;
431 		/* fill in line 3 of text */
432 		(void) sprintf(text2, "Job (%s) killed!\n",
433 		BASENAME(fullname, '/')+2);
434 		_CantContact[CANT2] = text2;
435 		if (*type == 'S') {
436 			if (EQUALSN(file1, "D.", 2))
437 				/* generated file (mail/news) I think */
438 				/* D. processing will return it later */
439 				continue;
440 
441 			/* some data was requested -- tell user */
442 
443 			(void) sprintf(text1, CMFMT, Myname, file1, Rmtname, file2,
444 				tp->tm_mon + 1, tp->tm_mday);
445 			_CantContact[CANT1] = text1;
446 			ret = sendMail((char *) NULL, user, "", _CantContact);
447 		}
448 		else if (*type == 'R') {
449 			(void) sprintf(text1, CMFMT, Rmtname, file1, Myname, file2,
450 				tp->tm_mon + 1, tp->tm_mday);
451 			_CantContact[CANT1] = text1;
452 			ret = sendMail((char *) NULL, user, "", _CantContact);
453 		}
454 	}
455 
456 	if (!*text) {
457 		(void) sprintf(text,
458 			"cprocess: C. %s, mail returned (%d), unlink(%s)",
459 			buf, ret, fullname);
460 	}
461 	DEBUG(3, "text (%s)\n", text);
462 
463 	errno = 0;
464 	(void) unlink(fullname);
465 	logit(text, errno);
466 
467 	(void) fclose(fp);
468 	return;
469 }
470 
471 /*
472  * wprocess - send warning messages for C. == Wdays
473  */
474 
475 void
476 wprocess(dir, file)
477 char *dir, *file;
478 {
479 	struct stat s;
480 	register struct tm *tp;
481 	char fullname[BUFSIZ], xfile[BUFSIZ], xF_file[BUFSIZ];
482 	char buf[BUFSIZ], user[BUFSIZ];
483 	char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256];
484 	char text[BUFSIZ], text1[BUFSIZ], text2[BUFSIZ];
485 	char *realuser, uline_m[NAMESIZE], uline_u[BUFSIZ], retaddr[BUFSIZ];
486 	FILE *fp, *xfp;
487 	int ret;
488 
489 	FULLNAME(fullname, dir, file);
490 	DEBUG(5, "wprocess(%s)\n", fullname);
491 
492 	fp = fopen(fullname, "r");
493 	if (fp == NULL) {
494 		DEBUG(4, "Can't open file (%s), ", fullname);
495 		DEBUG(4, "errno=%d -- skip it!\n", errno);
496 		return;
497 	}
498 
499 	if (fstat(fileno(fp), &s) != 0) {
500 
501 	/* can't happen; _age() did stat of this file and file is opened */
502 
503 		(void) fclose(fp);
504 		return;
505 	}
506 
507 	tp = localtime(&s.st_mtime);
508 
509 	if (s.st_size == 0) { /* dummy C. for polling */
510 		DEBUG(5, "dummy C. -- skip(%s)\n", fullname);
511 		(void) fclose(fp);
512 		return;
513 	}
514 
515 	/* read C. and process it */
516 	while (fgets(buf, BUFSIZ, fp) != NULL) {
517 		buf[strlen(buf)-1] = NULLCHAR; /* remove \n */
518 		if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2,
519 			user, opt, file3) <5) {
520 			DEBUG(5, "short line (%s): ", buf);
521 			DEBUG(5, "bad D. -- skip(%s)\n", fullname);
522 			(void) fclose(fp);
523 			return;
524 		}
525 
526 		/* set up the 6th text line of the mail message */
527 
528 		(void) sprintf(text2,
529 			"\nuucp job id is %s.\n", BASENAME(fullname, '/')+2);
530 
531 		_Warning[WARN2] = text2;
532 
533 		/* if Send type then do C. file processing */
534 
535 		if (*type == 'S') {
536 
537 		/* if this is a uux job - tell user about it */
538 
539 			if (EQUALSN(file2, "X.", 2)) {
540 				FULLNAME(xfile, dir, file1);
541 
542 				/* if X.file can't be read then skip it */
543 
544 				if ((xfp = fopen(xfile, "r")) == NULL) {
545 					DEBUG(3, "Can't read %s\n", xfile);
546 					break;
547 				}
548 				*retaddr = *uline_u = *uline_m = *text = NULLCHAR;
549 				while (fgets(buf, BUFSIZ, xfp) != NULL) {
550 
551 				/* remove \n from end of buffer */
552 
553 					buf[strlen(buf)-1] = NULLCHAR;
554 					switch(*buf) {
555 
556 					/* save the file name */
557 
558 					case 'F':
559 						FULLNAME(xF_file, dir, &buf[2]);
560 						break;
561 
562 					/* save return address */
563 
564 					case 'R':
565 						sscanf(buf+2, "%s", retaddr);
566 						DEBUG(7, "retaddr (%s)\n", retaddr);
567 						break;
568 
569 					/* save machine, user */
570 
571 					case 'U':
572 						sscanf(buf+2, "%s%s",
573 						    uline_u, uline_m);
574 						break;
575 					}
576 
577 					if (buf[0] != 'C')
578 						continue;
579 					realuser = uline_u;
580 					if (*retaddr != NULLCHAR)
581 						realuser = retaddr;
582 					if (*realuser == NULLCHAR)
583 						strcpy(realuser, user);
584 					if (!EQUALS(uline_m, Myname))
585 						sprintf(user, "%s!%s",
586 						    uline_m, realuser);
587 					else
588 						strcpy(user, realuser);
589 
590 					/* give mail special handling */
591 					if (EQUALSN(buf+2, "rmail ", 6))
592 						(void) sprintf(text1, XMFMT,
593 						    Rmtname, buf+8,
594 						    tp->tm_mon+1, tp->tm_mday);
595 					else
596 						(void) sprintf(text1, XFMT,
597 						    Rmtname, buf+2,
598 						    tp->tm_mon+1, tp->tm_mday);
599 
600 					_Warning[WARN1] = text1;
601 					if (EQUALSN(&buf[2], "rmail", 5))
602 						/*
603 						 * this is mail; append
604 						 * user mail (xF_file).
605 						 */
606 						ret = sendMail((char *) NULL,
607 						    user, xF_file, _Warning);
608 					else
609 						ret = sendMail((char *) NULL,
610 						    user, "", _Warning);
611 					break;
612 				}
613 				(void) fclose(xfp);
614 				break;
615 			}
616 
617 			/* if file1 is a D. file the it might be (mail/news) */
618 			/* if so then D. processing will take of it later */
619 
620 			if (EQUALSN(file1, "D.", 2))
621 				continue;
622 
623 			/* some data was requested -- tell user */
624 			/* set up the 2nd text line of the mail message */
625 
626 			(void) sprintf(text1, WFMT, Myname, file1, Rmtname, file2,
627 				tp->tm_mon + 1, tp->tm_mday);
628 			_Warning[WARN1] = text1;
629 			ret = sendMail((char *) NULL, user, "", _Warning);
630 		}
631 
632 		/* Receive C. file processing */
633 
634 		else if (*type == 'R') {
635 			if (EQUALSN(file1, "D.", 2) && EQUALSN(file2, "D.", 2))
636 				continue;
637 
638 			(void) sprintf(text1, WFMT, Rmtname, file1, Myname, file2,
639 				tp->tm_mon + 1, tp->tm_mday);
640 			_Warning[WARN1] = text1;
641 			ret = sendMail((char *) NULL, user, "", _Warning);
642 		}
643 	}	/* end while - read C. lines loop */
644 
645 	(void) sprintf(text,
646 		"wprocess: %s: %s, warning message sent to %s, returned (%d)",
647 		fullname, buf, user, ret);
648 
649 	DEBUG(3, "text (%s)\n", text);
650 
651 	logit(text, errno);
652 
653 	(void) fclose(fp);
654 	return;
655 }
656 /*
657  * oprocess - some unknown file just remove the file
658  */
659 
660 void
661 oprocess(fullname)
662 char *fullname;
663 {
664 
665 	char *p, text[BUFSIZ];
666 
667 	p = BASENAME(fullname, '/');
668 	if (EQUALSN(p, "P.", 2) == 0)
669 		if (_age(fullname) <= _Cdays)
670 			return;
671 	DEBUG(5, "oprocess(%s), ", fullname);
672 	DEBUG(5, "unlink(%s)\n", fullname);
673 	(void) sprintf(text, "oprocess: unlink(%s)", fullname);
674 	errno = 0;
675 	(void) unlink(fullname);
676 	logit(text, errno);
677 	return;
678 }
679 
680 /*
681  * dDprocess - random D. file (not mail or rnews)
682  *--just delete it for now
683  */
684 
685 void
686 dDprocess(fullname)
687 char *fullname;
688 {
689 	char text[BUFSIZ];
690 
691 	DEBUG(5, "dDprocess(%s), ", fullname);
692 	DEBUG(5, "unlink(%s)\n", fullname);
693 	(void) sprintf(text, "dDprocess: unlink(%s)", fullname);
694 	errno = 0;
695 	(void) unlink(fullname);
696 	logit(text, errno);
697 	return;
698 }
699 
700 /*
701  * dXprocess - process D. files that are destined for X. on remote
702  * --for now just delete it
703  */
704 
705 void
706 dXprocess(fullname)
707 char *fullname;
708 {
709 	char text[BUFSIZ];
710 
711 	DEBUG(5, "dXprocess(%s), ", fullname);
712 	DEBUG(5, "  unlink(%s)\n", fullname);
713 	(void) sprintf(text, "dXprocess: unlink(%s)", fullname);
714 	errno = 0;
715 	(void) unlink(fullname);
716 	logit(text, errno);
717 	return;
718 }
719 
720 /*
721  * dMprocess - process ophan D. mail files
722  * There are two types: ones generated locally and
723  * others that are from remotes.  They can be identified
724  * by the system name following the D.
725  * Local ones have the local name.
726  */
727 
728 void
729 dMprocess(dir, file)
730 char *dir, *file;
731 {
732 	int ret;
733 	char fullname[MAXFULLNAME];
734 	char *toUser, *toSystem;
735 	char text[BUFSIZ];
736 
737 	(void) sprintf(fullname, "%s/%s", dir, file);
738 	DEBUG(5, "dMprocess(%s)\n", fullname);
739 
740 
741 	if (PREFIX(_ShortLocal, &file[2])) {
742 		DEBUG(5, "  Local file %s: ", file);
743 	}
744 	else {
745 		DEBUG(5, "  Remote file %s: ", file);
746 	}
747 	if (toWho(fullname, &toUser, &toSystem)) {
748 		DEBUG(5, "toUser %s, ", toUser);
749 		DEBUG(5, "toSystem %s  ", toSystem);
750 		ret = sendMail(toSystem, toUser, fullname, _Undeliverable);
751 		DEBUG(5, "Mail sent, unlink(%s)\n", fullname);
752 		(void) sprintf(text,
753 			"dMprocess: mail %s to %s!%s, returned (%d),  unlink(%s)",
754 			fullname, toSystem, toUser, ret, fullname);
755 		errno = 0;
756 		(void) unlink(fullname);
757 		logit(text, errno);
758 	}
759 	return;
760 }
761 
762 /*
763  * dNprocess - process ophan D. netnews files
764  * There are two types: ones generated locally and
765  * others that are from remotes.  They can be identified
766  * by the system name following the D.
767  * Local ones have the local name.
768  */
769 
770 void
771 dNprocess(dir, file)
772 char *dir, *file;
773 {
774 	char fullname[MAXFULLNAME];
775 	char text[BUFSIZ];
776 	int ret;
777 
778 	(void) sprintf(fullname, "%s/%s", dir, file);
779 	DEBUG(5, "dNprocess(%s)\n", fullname);
780 
781 
782 	if (PREFIX(_ShortLocal, &file[2])) {
783 	/* just delete it, the C. is gone */
784 		DEBUG(5, "  Local file %s, ", file);
785 		DEBUG(5, "unlink(%s)\n", fullname);
786 		(void) unlink(fullname);
787 		(void) sprintf(text, "dNprocess: Local news item unlink(%s)",
788 			fullname);
789 		errno = 0;
790 		(void) unlink(fullname);
791 		logit(text, errno);
792 	}
793 	else {
794 	/* execute rnews with this file - the X. is missing */
795 		DEBUG(5, "  Remote file %s, ", file);
796 		DEBUG(5, "exec rnews(%s), ", fullname);
797 		ret = execRnews(fullname);
798 		DEBUG(5, "unlink(%s)\n", fullname);
799 		(void) sprintf(text,
800 			"dNprocess: Remote - exec rnews %s: returned (%d), unlink(%s)",
801 			fullname, ret, fullname);
802 		errno = 0;
803 		(void) unlink(fullname);
804 		logit(text, errno);
805 	}
806 	return;
807 }
808 
809 
810 
811 static long _sec_per_day = 86400L;
812 
813 /*
814  * _age - find the age of "file" in days
815  * return:
816  *	age of file
817  *	0 - if stat fails
818  */
819 
820 int
821 _age(fullname)
822 char *fullname;
823 {
824 	static time_t ptime = 0;
825 	time_t time();
826 	struct stat stbuf;
827 	int e;
828 
829 	if (!ptime)
830 		(void) time(&ptime);
831 	if (stat(fullname, &stbuf) != -1) {
832 		return ((int)((ptime - stbuf.st_mtime)/_sec_per_day));
833 	}
834 	e = errno;
835 	DEBUG(9, "_age: stat (%s) failed", fullname);
836 	DEBUG(9, ", errno %d\n", e);
837 	return(0);
838 }
839 
840 /*
841  * dType - return the type of D. file
842  * return:
843  *	FAIL - can't read D. file
844  *	D_MAIL - mail message D. file
845  *	D_NEWS - netnews D. file
846  *	D_DATA - other kind of D. file
847  *	D_XFILE - destined for X. on destination machine
848  */
849 
850 /* NLINES - number of lines of D. file to read to determine type */
851 #define NLINES	10
852 
853 int
854 dType(fullname)
855 char *fullname;
856 {
857 	char buf[BUFSIZ];
858 	FILE *fp;
859 	int i, type;
860 
861 	fp = fopen(fullname, "r");
862 	if (fp == NULL) {
863 		DEBUG(4, "Can't open file (%s), ", fullname);
864 		DEBUG(4, "errno=%d -- skip it!\n", errno);
865 		return(FAIL);
866 	}
867 	type = D_DATA;
868 
869 	/* read first NLINES lines to determine file type */
870 
871 	for (i=0; i<NLINES; i++) {
872 		if (fgets(buf, BUFSIZ, fp) == NULL)
873 			break;	/* no more lines */
874 		DEBUG(9, "buf: %s\n", buf);
875 		if (EQUALSN(buf, "From ", 5)) {
876 			type = D_MAIL;
877 			break;
878 		}
879 		if (EQUALSN(buf, "U ", 2)) {
880 			type = D_XFILE;
881 			break;
882 		}
883 		if (EQUALSN(buf, "Newsgroups: ", 12)) {
884 			type = D_NEWS;
885 			break;
886 		}
887 	}
888 
889 	(void) fclose(fp);
890 	return(type);
891 }
892 
893 /*
894  * sendMail - send mail file and message to user (local or remote)
895  * return:
896  *	the return from the pclose - mail exit status
897  */
898 int
899 sendMail(system, user, file, mtext)
900 char *system, *user, *file;
901 char *mtext[];
902 {
903 	register FILE *fp, *fi;
904 	char cmd[BUFSIZ];
905 	char *p;
906 
907 	DEBUG(5, "Mail %s to ", file);
908 	DEBUG(5, "%s\n", user);
909 
910 	/* get rid of some stuff that could be dangerous */
911 	if (system != NULL && (p = strpbrk(system, Shchar)) != NULL) {
912 		*p = NULLCHAR;
913 	}
914 	if (user != NULL && (p = strpbrk(user, Shchar)) != NULL) {
915 		*p = NULLCHAR;
916 	}
917 	if (system != NULL && *system != '\0')
918 		(void) sprintf(cmd, "%s %s '%s!%s'", PATH, MAIL, system, user);
919 	else
920 		(void) sprintf(cmd, "%s %s '%s'", PATH, MAIL, user);
921 
922 	DEBUG(7, "sendMail: %s\n", cmd);
923 	if ((fp = popen(cmd, "w")) == NULL)
924 		return(-errno);
925 	while (*mtext[0] )
926 		(void) fprintf(fp, *mtext++, Rmtname);
927 
928 	(void) fprintf(fp, "\n\tSincerely,\n\t%s!uucp\n", Myname);
929 	(void) fprintf(fp,
930 		"\n#############################################\n");
931 
932 	if (*file) {
933 	/*next statement should never happen;I read once */
934 		if ((fi= fopen(file, "r")) == NULL)
935 			return(pclose(fp));
936 		(void) fprintf(fp,
937 			"##### Data File: ############################\n");
938 		xfappend(fi, fp);
939 		(void) fclose(fi);
940 	}
941 	return(pclose(fp));
942 }
943 
944 /*
945  * execRnews - execute rnews command with stdin file
946  * return:
947  *	the return from the pclose - rnews exit status
948  */
949 int
950 execRnews(file)
951 char *file;
952 {
953 	register FILE *fp, *fi;
954 	char cmd[BUFSIZ];
955 
956 	DEBUG(5, "Rnews %s\n", file);
957 
958 	(void) sprintf(cmd, "%s rnews ", PATH);
959 	if ((fp = popen(cmd, "w")) == NULL)
960 		return(-errno);
961 
962 	if ( (fi = fopen(file, "r")) == NULL) /* never happen - I read once */
963 		return(pclose(fp));
964 	xfappend(fi, fp);
965 	(void) fclose(fi);
966 
967 	return(pclose(fp));
968 }
969 
970 /*
971  * toWho - figure out who to send this dead mail to
972  *	It is a guess;
973  *	If there is a local address, send it there.
974  *	If not, send it back where it came from.
975  * return:
976  *	0 - could not find system and user information
977  *	1 - found it
978  */
979 
980 int
981 toWho(file, user, system)
982 char *file;	/* the D. mail message file */
983 char **system;	/* pointer to the system name */
984 char **user;	/* pointer to the user name */
985 {
986 	char buf[BUFSIZ];
987 	FILE *fp;
988 	int i;
989 	static char fuser[BUFSIZ], fsystem[MAXBASENAME+1];  /* from first From */
990 	static char luser[BUFSIZ], lsystem[MAXBASENAME+1];  /* from other From */
991 
992 	*fuser = NULLCHAR;
993 	DEBUG(5, "toWho(%s)\n", file);
994 	fp = fopen(file, "r");
995 	for (i=0; i<NLINES; i++) {
996 		if (fgets(buf, BUFSIZ, fp) == NULL)
997 			break;	/* no more lines */
998 		DEBUG(9, "buf: %s\n", buf);
999 		if (!analFrom(buf, luser, lsystem))
1000 			continue;
1001 		if ( !*fuser) {
1002 			(void) strcpy(fuser, luser);
1003 			(void) strcpy(fsystem, lsystem);
1004 		}
1005 		if (EQUALS(Myname, lsystem)) {
1006 			*user = luser;
1007 			*system = lsystem;
1008 			(void) fclose(fp);
1009 			return(1);
1010 		}
1011 	}
1012 
1013 	/* could not find local user - use first line */
1014 	(void) fclose(fp);
1015 	if (!*fuser)	/* didn't find all information */
1016 		return(0);
1017 	*user = fuser;
1018 	*system = fsystem;
1019 	return(1);
1020 }
1021 
1022 /* analFrom - analyze From line
1023  * return:
1024  *	0 - didn't find both from and remote from info
1025  *	1 - found info.
1026  */
1027 
1028 int
1029 analFrom(line, user, system)
1030 char *line, *user, *system;
1031 {
1032 	char *s;
1033 	int i;
1034 
1035 	if (!PREFIX("From ", line) && !PREFIX(">From ", line))
1036 		return(0);
1037 
1038 	s = strchr(line, ' ') + 1;
1039 	for (i = 0;  *s && *s != ' ' && *s != '\n'; i++)
1040 		user[i] = *s++;
1041 	user[i] = NULLCHAR;
1042 
1043 	/* look for "remote from" */
1044 	while (*s && ((s = strchr(s, ' ')) != NULL)) {
1045 		s++;
1046 		if (PREFIX("remote from ", s)) {	/* found it */
1047 			s = s + strlen("remote from ");
1048 			for (i = 0; (i<MAXBASENAME) && *s && *s != ' ' && *s != '\n'; i++)
1049 				system[i] = *s++;
1050 			system[i] = NULLCHAR;
1051 			return(1);
1052 		}
1053 	}
1054 	return(0);
1055 }
1056 
1057 
1058 
1059 static FILE	*_Lf = NULL;
1060 
1061 /*
1062  * Make log entry
1063  *	text	-> ptr to text string
1064  *	status	errno number
1065  * Returns:
1066  *	none
1067  */
1068 
1069 void
1070 logit(text, status)
1071 register char	*text;
1072 int status;
1073 {
1074 
1075 	if (Nstat.t_pid == 0)
1076 		Nstat.t_pid = getpid();
1077 
1078 	if (_Lf == NULL) {
1079 		_Lf = fopen(Logfile, "a");
1080 		(void) chmod(Logfile, LOGFILEMODE);
1081 		if (_Lf == NULL)
1082 			return;
1083 		setbuf(_Lf, CNULL);
1084 	}
1085 	(void) fseek(_Lf, 0L, 2);
1086 	(void) fprintf(_Lf, "%s ", Rmtname);
1087 	(void) fprintf(_Lf, "(%s,%ld,%d) ", timeStamp(), (long) Nstat.t_pid, Seqn);
1088 	(void) fprintf(_Lf, "%s (%d)\n", text, status);
1089 	return;
1090 }
1091 
1092 cleanworkspace()
1093 {
1094 	DIR	*spooldir;
1095 	char f[MAXFULLNAME];
1096 
1097 	if (chdir(WORKSPACE) != 0) {
1098 		(void) fprintf(stderr, "CAN'T CHDIR (%s): errno (%d)\n", WORKSPACE, errno);
1099 		return;
1100 	}
1101 	if ((spooldir = opendir(WORKSPACE)) == NULL) {
1102 		(void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n", WORKSPACE, errno);
1103 		return;
1104 	}
1105 
1106 	while (gnamef(spooldir, f) == TRUE)
1107 		if (_age(f) >= 1)
1108 			if (unlink(f) != 0)
1109 				(void) fprintf(stderr, "CAN'T UNLINK (%s): errno (%d)\n", f, errno);
1110 
1111 }
1112