Home | History | Annotate | Download | only in bnu
      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