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