xref: /csrg-svn/libexec/bugfiler/bugfiler.c (revision 14552)
1*14552Ssam #ifndef lint
2*14552Ssam static char sccsid[] = "@(#)bugfiler.c	4.4 (Berkeley) 08/11/83";
3*14552Ssam #endif
4*14552Ssam 
512375Sralph /*
612375Sralph  * Bug report processing program.
712375Sralph  * It is designed to be invoked by alias(5) and to be compatible with mh.
812375Sralph  */
912375Sralph 
1012375Sralph #include <stdio.h>
1112375Sralph #include <ctype.h>
1212375Sralph #include <signal.h>
1312375Sralph #include <sys/types.h>
1412375Sralph #include <sys/stat.h>
1512695Sralph #include <sys/dir.h>
1612375Sralph 
1712375Sralph char	deliver[] = "/usr/local/lib/mh/deliver";
1812375Sralph char	unixtomh[] = "/usr/local/lib/mh/unixtomh";
1912375Sralph char	*maildir = "/ra/bugs/mail";
2012375Sralph char	ackfile[] = ".ack";
2112375Sralph char	errfile[] = ".format";
2212375Sralph char	sumfile[] = "summary";
2312375Sralph char	logfile[] = "errors/log";
2412375Sralph char	tmpname[] = "BfXXXXXX";
2512375Sralph char	draft[] = "RpXXXXXX";
2612375Sralph 
2712695Sralph char	buf[8192];
2812375Sralph char	folder[MAXNAMLEN];
2912375Sralph int	num;
3012375Sralph int	msg_prot = 0664;
3112375Sralph 
3212375Sralph int	debug;
3312375Sralph 
3412375Sralph char	*index();
3512375Sralph char	*rindex();
3612375Sralph char	*fixaddr();
3712375Sralph 
3812375Sralph main(argc, argv)
3912375Sralph 	char *argv[];
4012375Sralph {
4112375Sralph 	register char *cp;
4212695Sralph 	register int n;
4312695Sralph 	int pfd[2];
4412375Sralph 
4512375Sralph 	if (argc > 3) {
4612375Sralph 	usage:
4712695Sralph 		fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n");
4812375Sralph 		exit(1);
4912375Sralph 	}
5012375Sralph 	while (--argc > 0) {
5112375Sralph 		cp = *++argv;
5212695Sralph 		if (*cp == '-')
5312695Sralph 			switch (cp[1]) {
5412375Sralph 			case 'd':
5512375Sralph 				debug++;
5612375Sralph 				break;
5712695Sralph 
5812695Sralph 			case 'm':	/* set message protection */
5912695Sralph 				n = 0;
6012695Sralph 				for (cp += 2; *cp >= '0' && *cp <= '7'; )
6112695Sralph 					n = (n << 3) + (*cp++ - '0');
6212695Sralph 				msg_prot = n & 0777;
6312695Sralph 				break;
6412695Sralph 
6512375Sralph 			default:
6612375Sralph 				goto usage;
6712375Sralph 			}
6812375Sralph 		else
6912375Sralph 			maildir = cp;
7012375Sralph 	}
7112695Sralph 	if (!debug)
7212695Sralph 		freopen(logfile, "a", stderr);
7312695Sralph 
7412375Sralph 	if (chdir(maildir) < 0) {
7512375Sralph 		fprintf(stderr, "can't chdir to %s\n", maildir);
7612375Sralph 		exit(1);
7712375Sralph 	}
7812695Sralph 	umask(0);
7912695Sralph 
8012695Sralph #ifdef UNIXCOMP
8112695Sralph 	/*
8212695Sralph 	 * Convert UNIX style mail to mh style by filtering stdin through
8312695Sralph 	 * unixtomh.
8412695Sralph 	 */
8512695Sralph 	if (pipe(pfd) >= 0) {
8612695Sralph 		while ((n = fork()) == -1)
8712695Sralph 			sleep(5);
8812695Sralph 		if (n == 0) {
8912695Sralph 			close(pfd[0]);
9012695Sralph 			dup2(pfd[1], 1);
9112695Sralph 			close(pfd[1]);
9212695Sralph 			execl(unixtomh, "unixtomh", 0);
9312695Sralph 			_exit(127);
9412695Sralph 		}
9512695Sralph 		close(pfd[1]);
9612695Sralph 		dup2(pfd[0], 0);
9712695Sralph 		close(pfd[0]);
9812695Sralph 	}
9912695Sralph #endif
10012695Sralph 	while (process())
10112695Sralph 		;
10212695Sralph 	exit(0);
10312375Sralph }
10412375Sralph 
10512695Sralph /* states */
10612695Sralph 
10712695Sralph #define EOM	0	/* End of message seen */
10812695Sralph #define FLD	1	/* Looking for header lines */
10912695Sralph #define BODY	2	/* Looking for message body lines */
11012695Sralph 
11112375Sralph /* defines used for tag attributes */
11212375Sralph 
11312375Sralph #define H_REQ 01
11412695Sralph #define H_SAV 02
11512695Sralph #define H_HDR 04
11612695Sralph #define H_FND 010
11712375Sralph 
11812375Sralph #define FROM_I headers[0].h_info
11912375Sralph #define SUBJECT_I headers[1].h_info
12012375Sralph #define INDEX &headers[2]
12112375Sralph #define INDEX_I headers[2].h_info
12212375Sralph #define DATE_I headers[3].h_info
12312375Sralph #define MSGID_I headers[4].h_info
12412375Sralph #define REPLYTO_I headers[5].h_info
12512375Sralph #define RETURNPATH_I headers[6].h_info
12612375Sralph #define TO_I headers[7].h_info
12712375Sralph #define CC_I headers[8].h_info
12812375Sralph #define FIX headers[11]
12912375Sralph 
13012375Sralph struct header {
13112375Sralph 	char	*h_tag;
13212375Sralph 	int	h_flags;
13312375Sralph 	char	*h_info;
13412375Sralph } headers[] = {
13512695Sralph 	"From",		H_REQ|H_SAV|H_HDR, 0,
13612695Sralph 	"Subject",	H_REQ|H_SAV|H_HDR, 0,
13712375Sralph 	"Index",	H_REQ|H_SAV, 0,
13812695Sralph 	"Date",		H_SAV|H_HDR, 0,
13912695Sralph 	"Message-Id",	H_SAV|H_HDR, 0,
14012695Sralph 	"Reply-To",	H_SAV|H_HDR, 0,
14112695Sralph 	"Return-Path",	H_SAV|H_HDR, 0,
14212695Sralph 	"To",		H_SAV|H_HDR, 0,
14312695Sralph 	"Cc",		H_SAV|H_HDR, 0,
14412375Sralph 	"Description",	H_REQ,       0,
14512375Sralph 	"Repeat-By",	H_REQ,	     0,
14612695Sralph 	"Fix",		0,	     0,
14712375Sralph 	0,	0,	0,
14812375Sralph };
14912375Sralph 
15012695Sralph struct header *findheader();
15112695Sralph 
15212375Sralph process()
15312375Sralph {
15412375Sralph 	register struct header *hp;
15512375Sralph 	register char *cp;
15612695Sralph 	register int c;
15712375Sralph 	char *info;
15812695Sralph 	int state, tmp;
15912695Sralph 	FILE *tfp, *fs;
16012375Sralph 
16112375Sralph 	/*
16212375Sralph 	 * Insure all headers are in a consistent
16312375Sralph 	 * state.  Anything left there is free'd.
16412375Sralph 	 */
16512375Sralph 	for (hp = headers; hp->h_tag; hp++) {
16612695Sralph 		hp->h_flags &= ~H_FND;
16712375Sralph 		if (hp->h_info) {
16812695Sralph 			free(hp->h_info);
16912375Sralph 			hp->h_info = 0;
17012375Sralph 		}
17112375Sralph 	}
17212375Sralph 	/*
17312375Sralph 	 * Read the report and make a copy.  Must conform to RFC822 and
17412375Sralph 	 * be of the form... <tag>: <info>
17512695Sralph 	 * Note that the input is expected to be in mh mail format
17612695Sralph 	 * (i.e., messages are separated by lines of ^A's).
17712375Sralph 	 */
17812695Sralph 	while ((c = getchar()) == '\001' && peekc(stdin) == '\001')
17912695Sralph 		while (getchar() != '\n')
18012695Sralph 			;
18112695Sralph 	if (c == EOF)
18212695Sralph 		return(0);	/* all done */
18312695Sralph 
18412375Sralph 	mktemp(tmpname);
18512695Sralph 	if ((tmp = creat(tmpname, msg_prot)) < 0) {
18612695Sralph 		fprintf(stderr, "cannont create %s\n", tmpname);
18712695Sralph 		exit(1);
18812695Sralph 	}
18912695Sralph 	if ((tfp = fdopen(tmp, "w")) == NULL) {
19012695Sralph 		fprintf(stderr, "cannot fdopen temp file\n");
19112695Sralph 		exit(1);
19212695Sralph 	}
19312695Sralph 
19412695Sralph 	for (state = FLD; state != EOF && state != EOM; c = getchar()) {
19512695Sralph 		switch (state) {
19612695Sralph 		case FLD:
19712695Sralph 			if (c == '\n' || c == '-')
19812695Sralph 				goto body;
19912695Sralph 			for (cp = buf; c != ':'; c = getchar()) {
20012695Sralph 				if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) {
20112695Sralph 					*cp++ = c;
20212695Sralph 					continue;
20312695Sralph 				}
20412695Sralph 				*cp = '\0';
20512695Sralph 				fputs(buf, tfp);
20612695Sralph 				state = EOF;
20712695Sralph 				while (c != EOF) {
20812695Sralph 					if (c == '\n')
20912695Sralph 						if ((tmp = peekc(stdin)) == EOF)
21012695Sralph 							break;
21112695Sralph 						else if (tmp == '\001') {
21212695Sralph 							state = EOM;
21312695Sralph 							break;
21412695Sralph 						}
21512695Sralph 					putc(c, tfp);
21612695Sralph 					c = getchar();
21712695Sralph 				}
21812695Sralph 				fclose(tfp);
21912695Sralph 				goto badfmt;
22012695Sralph 			}
22112695Sralph 			*cp = '\0';
22212695Sralph 			fprintf(tfp, "%s:", buf);
22312695Sralph 			hp = findheader(buf, state);
22412695Sralph 
22512695Sralph 			for (cp = buf; ; ) {
22612695Sralph 				if (cp >= buf+sizeof(buf)-1) {
22712695Sralph 					fprintf(stderr, "field truncated\n");
22812695Sralph 					while ((c = getchar()) != EOF && c != '\n')
22912695Sralph 						putc(c, tfp);
23012695Sralph 				}
23112695Sralph 				if ((c = getchar()) == EOF) {
23212695Sralph 					state = EOF;
23312695Sralph 					break;
23412695Sralph 				}
23512695Sralph 				putc(c, tfp);
23612695Sralph 				*cp++ = c;
23712695Sralph 				if (c == '\n')
23812695Sralph 					if ((c = peekc(stdin)) != ' ' && c != '\t') {
23912695Sralph 						if (c == EOF)
24012695Sralph 							state = EOF;
24112695Sralph 						else if (c == '\001')
24212695Sralph 							state = EOM;
24312695Sralph 						break;
24412695Sralph 					}
24512695Sralph 			}
24612695Sralph 			*cp = '\0';
24712695Sralph 			cp = buf;
24812695Sralph 			break;
24912695Sralph 
25012695Sralph 		body:
25112695Sralph 			state = BODY;
25212695Sralph 		case BODY:
25312695Sralph 			for (cp = buf; ; c = getchar()) {
25412695Sralph 				if (c == EOF) {
25512695Sralph 					state = EOF;
25612695Sralph 					break;
25712695Sralph 				}
25812695Sralph 				if (c == '\001' && peekc(stdin) == '\001') {
25912695Sralph 					state = EOM;
26012695Sralph 					break;
26112695Sralph 				}
26212695Sralph 				putc(c, tfp);
26312695Sralph 				*cp++ = c;
26412695Sralph 				if (cp >= buf+sizeof(buf)-1 || c == '\n')
26512695Sralph 					break;
26612695Sralph 			}
26712695Sralph 			*cp = '\0';
26812695Sralph 			if ((cp = index(buf, ':')) == NULL)
26912695Sralph 				continue;
27012695Sralph 			*cp++ = '\0';
27112695Sralph 			hp = findheader(buf, state);
27212695Sralph 		}
27312695Sralph 
27412695Sralph 		/*
27512695Sralph 		 * Don't save the info if the header wasn't found, we don't
27612695Sralph 		 * care about the info, or the header is repeated.
27712695Sralph 		 */
27812695Sralph 		if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info)
27912375Sralph 			continue;
28012375Sralph 		while (isspace(*cp))
28112375Sralph 			cp++;
28212375Sralph 		if (*cp) {
28312375Sralph 			info = cp;
28412375Sralph 			while (*cp++);
28512375Sralph 			cp--;
28612375Sralph 			while (isspace(cp[-1]))
28712375Sralph 				*--cp = '\0';
28812375Sralph 			hp->h_info = (char *) malloc(strlen(info) + 1);
28912695Sralph 			if (hp->h_info == NULL) {
29012695Sralph 				fprintf(stderr, "ran out of memory\n");
29112375Sralph 				continue;
29212695Sralph 			}
29312375Sralph 			strcpy(hp->h_info, info);
29412375Sralph 			if (hp == INDEX)
29512375Sralph 				chkindex(hp);
29612375Sralph 		}
29712375Sralph 	}
29812695Sralph 	fclose(tfp);
29912375Sralph 	/*
30012375Sralph 	 * Verify all the required pieces of information
30112375Sralph 	 * are present.
30212375Sralph 	 */
30312695Sralph 	for (hp = headers; hp->h_tag; hp++) {
30412375Sralph 		/*
30512375Sralph 		 * Mail the bug report back to the sender with a note
30612375Sralph 		 * explaining they must conform to the specification.
30712375Sralph 		 */
30812695Sralph 		if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) {
30912695Sralph 			if (debug)
31012695Sralph 				printf("Missing %s\n", hp->h_tag);
31112695Sralph 		badfmt:
31212695Sralph 			reply(FROM_I, errfile, tmpname);
31312695Sralph 			file(tmpname, "errors");
31412695Sralph 			return(state == EOM);
31512695Sralph 		}
31612375Sralph 	}
31712375Sralph 	/*
31812695Sralph 	 * Acknowledge receipt.
31912695Sralph 	 */
32012695Sralph 	reply(FROM_I, ackfile, (char *)0);
32112695Sralph 	file(tmpname, folder);
32212695Sralph 	/*
32312375Sralph 	 * Append information about the new bug report
32412375Sralph 	 * to the summary file.
32512375Sralph 	 */
32612695Sralph 	if ((fs = fopen(sumfile, "a")) == NULL)
32712375Sralph 		fprintf(stderr, "Can't open %s\n", sumfile);
32812695Sralph 	else {
32912695Sralph 		fprintf(fs, "%14.14s/%-3d  ", folder, num);
33012695Sralph 		fprintf(fs, "%-51.51s Recv\n", INDEX_I);
33112695Sralph 		fprintf(fs, "\t\t    %-51.51s\n", SUBJECT_I);
33212375Sralph 	}
33312375Sralph 	fclose(fs);
33412695Sralph 	return(state == EOM);
33512375Sralph }
33612375Sralph 
33712375Sralph /*
33812695Sralph  * Lookup the string in the list of headers and return a pointer
33912695Sralph  * to the entry or NULL.
34012695Sralph  */
34112695Sralph 
34212695Sralph struct header *
34312695Sralph findheader(name, state)
34412695Sralph 	char *name;
34512695Sralph 	int state;
34612695Sralph {
34712695Sralph 	register struct header *hp;
34812695Sralph 
34912695Sralph 	if (debug)
35012695Sralph 		printf("findheader(%s, %d)\n", name, state);
35112695Sralph 
35212695Sralph 	for (hp = headers; hp->h_tag; hp++) {
35312695Sralph 		if (!streq(hp->h_tag, buf))
35412695Sralph 			continue;
35512695Sralph 		if ((hp->h_flags & H_HDR) && state != FLD)
35612695Sralph 			continue;
35712695Sralph 		hp->h_flags |= H_FND;
35812695Sralph 		return(hp);
35912695Sralph 	}
36012695Sralph 	return(NULL);
36112695Sralph }
36212695Sralph 
36312695Sralph /*
36412375Sralph  * Check the format of the Index information.
36512375Sralph  * A side effect is to set the name of the folder if all is well.
36612375Sralph  */
36712375Sralph 
36812375Sralph chkindex(hp)
36912375Sralph 	struct header *hp;
37012375Sralph {
37112695Sralph 	register char *cp1, *cp2;
37212375Sralph 	register char c;
37312375Sralph 	struct stat stbuf;
37412375Sralph 
37512375Sralph 	if (debug)
37612695Sralph 		printf("chkindex(%s)\n", hp->h_info);
37712375Sralph 	/*
37812695Sralph 	 * Strip of leading "/", "usr/", "src/" or "sys/".
37912695Sralph 	 */
38012695Sralph 	cp1 = hp->h_info;
38112695Sralph 	while (*cp1 == '/')
38212695Sralph 		cp1++;
38312695Sralph 	while (substr(cp1, "usr/") || substr(cp1, "src/") || substr(cp1, "sys/"))
38412695Sralph 		cp1 += 4;
38512695Sralph 	/*
38612375Sralph 	 * Read the folder name and remove it from the index line.
38712375Sralph 	 */
38812695Sralph 	for (cp2 = folder; ;) {
38912695Sralph 		switch (c = *cp1++) {
39012695Sralph 		case '/':
39112695Sralph 			if (cp2 == folder)
39212695Sralph 				continue;
39312375Sralph 			break;
39412695Sralph 		case '\0':
39512695Sralph 			cp1--;
39612695Sralph 			break;
39712695Sralph 		case ' ':
39812695Sralph 		case '\t':
39912695Sralph 			while (isspace(*cp1))
40012695Sralph 				cp1++;
40112695Sralph 			break;
40212695Sralph 		default:
40312695Sralph 			if (cp2 < folder+sizeof(folder)-1)
40412695Sralph 				*cp2++ = c;
40512695Sralph 			continue;
40612375Sralph 		}
40712695Sralph 		*cp2 = '\0';
40812695Sralph 		for (cp2 = hp->h_info; *cp2++ = *cp1++; )
40912695Sralph 			;
41012695Sralph 		break;
41112375Sralph 	}
41212695Sralph 	if (debug)
41312695Sralph 		printf("folder = %s\n", folder);
41412375Sralph 	/*
41512375Sralph 	 * Check to make sure we have a valid folder name
41612375Sralph 	 */
41712375Sralph 	if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR)
41812375Sralph 		return;
41912375Sralph 	/*
42012375Sralph 	 * The Index line is not in the correct format so clear
42112695Sralph 	 * the H_FND flag to mail back the correct format.
42212375Sralph 	 */
42312695Sralph 	hp->h_flags &= ~H_FND;
42412375Sralph }
42512375Sralph 
42612375Sralph /*
42712375Sralph  * Move or copy the file msg to the folder (directory).
42812375Sralph  * A side effect is to set num to the number of the file in folder.
42912375Sralph  */
43012375Sralph 
43112375Sralph file(fname, folder)
43212375Sralph 	char *fname, *folder;
43312375Sralph {
43412375Sralph 	register char *cp, n;
43512375Sralph 	char msgname[MAXNAMLEN*2+2];
43612375Sralph 	struct stat stbuf;
43712375Sralph 	DIR *dirp;
43812375Sralph 	struct direct *d;
43912375Sralph 
44012375Sralph 	if (debug)
44112695Sralph 		printf("file(%s, %s)\n", fname, folder);
44212375Sralph 	/*
44312375Sralph 	 * Get the next number to use by finding the last message number
44412375Sralph 	 * in folder and adding one.
44512375Sralph 	 */
44612375Sralph 	if ((dirp = opendir(folder)) == NULL) {
44712375Sralph 		fprintf(stderr, "Cannot open %s/%s\n", maildir, folder);
44812375Sralph 		return;
44912375Sralph 	}
45012375Sralph 	num = 0;
45112375Sralph 	while ((d = readdir(dirp)) != NULL) {
45212375Sralph 		cp = d->d_name;
45312375Sralph 		n = 0;
45412375Sralph 		while (isdigit(*cp))
45512375Sralph 			n = n * 10 + (*cp++ - '0');
45612375Sralph 		if (*cp == '\0' && n > num)
45712375Sralph 			num = n;
45812375Sralph 	}
45912375Sralph 	closedir(dirp);
46012375Sralph 	num++;
46112375Sralph 	/*
46212375Sralph 	 * Create the destination file "folder/num" and copy fname to it.
46312375Sralph 	 */
46412375Sralph 	sprintf(msgname, "%s/%d", folder, num);
46512375Sralph 	if (link(fname, msgname) < 0) {
46612375Sralph 		int fin, fout;
46712375Sralph 
46812695Sralph 		if ((fin = open(fname, 0)) < 0) {
46912695Sralph 			fprintf(stderr, "cannot open %s\n", fname);
47012375Sralph 			return;
47112695Sralph 		}
47212695Sralph 		if ((fout = creat(msgname, msg_prot)) < 0) {
47312695Sralph 			fprintf(stderr, "cannot create %s\n", msgname);
47412375Sralph 			return;
47512695Sralph 		}
47612695Sralph 		while ((n = read(fin, buf, sizeof(buf))) > 0)
47712695Sralph 			write(fout, buf, n);
47812375Sralph 		close(fin);
47912375Sralph 		close(fout);
48012375Sralph 	}
48112375Sralph 	unlink(fname);
48212375Sralph }
48312375Sralph 
48412375Sralph /*
48512375Sralph  * Mail file1 and file2 back to the sender.
48612375Sralph  */
48712375Sralph 
48812375Sralph reply(to, file1, file2)
48912375Sralph 	char	*to, *file1, *file2;
49012375Sralph {
49112375Sralph 	int (*istat)(), (*qstat)();
49212375Sralph 	int pid, w, status, pfd[2], in;
49312375Sralph 	FILE *fout;
49412375Sralph 
49512375Sralph 	if (debug)
49612695Sralph 		printf("reply(%s, %s, %s)\n", to, file1, file2);
49712695Sralph 
49812375Sralph 	/*
49912375Sralph 	 * Create a temporary file to put the message in.
50012375Sralph 	 */
50112375Sralph 	mktemp(draft);
50212375Sralph 	if ((fout = fopen(draft, "w")) == NULL) {
50312375Sralph 		fprintf(stderr, "Can't create %s\n", draft);
50412375Sralph 		return;
50512375Sralph 	}
50612375Sralph 	/*
50712375Sralph 	 * Output the proper header information.
50812375Sralph 	 */
50914342Skarels 	fprintf(fout, "Reply-To: 4bsd-bugs%%ucbarpa@BERKELEY\n");
51012375Sralph 	if (RETURNPATH_I != NULL)
51112375Sralph 		to = RETURNPATH_I;
51212375Sralph 	if (REPLYTO_I != NULL)
51312375Sralph 		to = REPLYTO_I;
51412375Sralph 	if ((to = fixaddr(to)) == 0) {
51512375Sralph 		fprintf(stderr, "No one to reply to\n");
51612375Sralph 		return;
51712375Sralph 	}
51812375Sralph 	fprintf(fout, "To: %s\n", to);
51912375Sralph 	if (SUBJECT_I) {
52012375Sralph 		fprintf(fout, "Subject: ");
52112375Sralph 		if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') ||
52212375Sralph 		    (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') ||
52312375Sralph 		    SUBJECT_I[2] != ':')
52412375Sralph 			fprintf(fout, "Re: ");
52512375Sralph 		fprintf(fout, "%s\n", SUBJECT_I);
52612375Sralph 	}
52712375Sralph 	if (DATE_I) {
52812375Sralph 		fprintf(fout, "In-Acknowledgement-Of: Your message of ");
52912375Sralph 		fprintf(fout, "%s.\n", DATE_I);
53012375Sralph 		if (MSGID_I)
53112375Sralph 			fprintf(fout, "             %s\n", MSGID_I);
53212375Sralph 	}
53312375Sralph 	fprintf(fout, "----------\n");
53412375Sralph 	if ((in = open(file1, 0)) >= 0) {
53512695Sralph 		while ((w = read(in, buf, sizeof(buf))) > 0)
53612695Sralph 			fwrite(buf, 1, w, fout);
53712375Sralph 		close(in);
53812375Sralph 	}
53912375Sralph 	if (file2 && (in = open(file2, 0)) >= 0) {
54012695Sralph 		while ((w = read(in, buf, sizeof(buf))) > 0)
54112695Sralph 			fwrite(buf, 1, w, fout);
54212375Sralph 		close(in);
54312375Sralph 	}
54412375Sralph 	fclose(fout);
54512375Sralph 	while ((pid = fork()) == -1)
54612375Sralph 		sleep(5);
54712375Sralph 	if (pid == 0) {
54812375Sralph 		execl(deliver, "deliver", draft, 0);
54912375Sralph 		_exit(127);
55012375Sralph 	}
55112375Sralph 	istat = signal(SIGINT, SIG_IGN);
55212375Sralph 	qstat = signal(SIGQUIT, SIG_IGN);
55312375Sralph 	while ((w = wait(&status)) != -1 && w != pid);
55412375Sralph 	signal(SIGINT, istat);
55512375Sralph 	signal(SIGQUIT, qstat);
55612375Sralph 	if (w != -1 && status == 0)
55712375Sralph 		unlink(draft);
55812375Sralph }
55912375Sralph 
56012375Sralph /*
56112375Sralph  * fix names like "xxx (something)" to "xxx" and
56212375Sralph  * "xxx <something>" to "something".
56312375Sralph  */
56412375Sralph 
56512375Sralph char *
56612375Sralph fixaddr(text)
56712375Sralph 	char *text;
56812375Sralph {
56912375Sralph 	register char *cp, *lp, c;
57012375Sralph 	char *tp;
57112375Sralph 
57212375Sralph 	if (!text)
57312375Sralph 		return(0);
57412375Sralph 	for (lp = cp = text; ; ) {
57512375Sralph 		switch (c = *cp++) {
57612375Sralph 		case '(':
57712375Sralph 			while (*cp && *cp++ != ')');
57812375Sralph 			continue;
57912375Sralph 		case '<':
58012375Sralph 			lp = text;
58112375Sralph 		case '>':
58212375Sralph 			continue;
58312375Sralph 		case '\0':
58412375Sralph 			while (lp != text && (*lp == ' ' || *lp == '\t'))
58512375Sralph 				lp--;
58612375Sralph 			*lp = c;
58712375Sralph 			return(text);
58812375Sralph 		}
58912375Sralph 		*lp++ = c;
59012375Sralph 	}
59112375Sralph }
59212375Sralph 
59312375Sralph /*
59412375Sralph  * Compare two strings and convert any upper case letters to lower case.
59512375Sralph  */
59612375Sralph 
59712695Sralph streq(s1, s2)
59812695Sralph 	register char *s1, *s2;
59912375Sralph {
60012375Sralph 	register int c;
60112375Sralph 
60212695Sralph 	while (c = *s1++)
60312695Sralph 		if ((c | 040) != (*s2++ | 040))
60412375Sralph 			return(0);
60512695Sralph 	return(*s2 == '\0');
60612375Sralph }
60712695Sralph 
60812695Sralph /*
60912695Sralph  * Return true if string s2 matches the first part of s1.
61012695Sralph  */
61112695Sralph 
61212695Sralph substr(s1, s2)
61312695Sralph 	register char *s1, *s2;
61412695Sralph {
61512695Sralph 	register int c;
61612695Sralph 
61712695Sralph 	while (c = *s2++)
61812695Sralph 		if (c != *s1++)
61912695Sralph 			return(0);
62012695Sralph 	return(1);
62112695Sralph }
62212695Sralph 
62312695Sralph peekc(fp)
62412695Sralph FILE *fp;
62512695Sralph {
62612695Sralph 	register c;
62712695Sralph 
62812695Sralph 	c = getc(fp);
62912695Sralph 	ungetc(c, fp);
63012695Sralph 	return(c);
63112695Sralph }
632