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