1*55419Seric /*
2*55419Seric  * Copyright (c) 1992 Eric P. Allman
3*55419Seric  * Copyright (c) 1992 Regents of the University of California.
4*55419Seric  * All rights reserved.
5*55419Seric  *
6*55419Seric  * %sccs.include.redist.c%
7*55419Seric  */
8*55419Seric 
9*55419Seric #ifndef lint
10*55419Seric char copyright[] =
11*55419Seric "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
12*55419Seric  All rights reserved.\n";
13*55419Seric static char sccsid[] = "@(#)mldistrib.c	5.6 (Berkeley) 07/20/92";
14*55419Seric #endif /* not lint */
15*55419Seric 
1651590Skarels #include <sys/types.h>
1742162Skarels #include <stdio.h>
1842162Skarels #include <ctype.h>
1942162Skarels #include <sysexits.h>
2042162Skarels #include <paths.h>
2142162Skarels 
2242162Skarels #define TRUE		1
2342162Skarels #define FALSE		0
2442162Skarels typedef char		BOOL;
2542162Skarels 
2642162Skarels #define CHARNULL	((char *) NULL)
2742163Skarels #define MAXMAILOPTS	20
2842162Skarels 
2942162Skarels enum copymode {RETAIN, DISCARD};
3042163Skarels char *myname;
3151590Skarels int  debug;
3242162Skarels 
main(argc,argv)3342162Skarels main(argc, argv)
3442162Skarels 	int argc;
3542162Skarels 	char **argv;
3642162Skarels {
3742162Skarels 	BOOL seen_precedence;
3842162Skarels 	register FILE *mailfp;
3942162Skarels 	enum copymode mode;
4042162Skarels 	register char *p;
4142162Skarels 	char *ml_name;
4242162Skarels 	char *ml_owner;
4342163Skarels 	char *mailer_opts[MAXMAILOPTS+1];
4442163Skarels 	char **next_opt = mailer_opts;
4542162Skarels 	char c;
4642162Skarels 	extern FILE *openmailer();
4742162Skarels 	extern char *readheadertag();
4842162Skarels 	extern void copyheader();
4942162Skarels 	extern void dropheader();
5042162Skarels 	extern void copybody();
5142162Skarels 
5242163Skarels 	myname = argv[0];
5342163Skarels 	argc--, argv++;
5442163Skarels 	while (*argv[0] == '-')
5542163Skarels 	{
5651590Skarels 		if (strcmp(argv[0], "-d") == 0)
5751590Skarels 		{
5851590Skarels 			debug++;
5951590Skarels 			argv++;
6051590Skarels 			argc--;
6151590Skarels 			continue;
6251590Skarels 		}
6342163Skarels 		if (next_opt >= &mailer_opts[MAXMAILOPTS])
6442163Skarels 		{
6542163Skarels 			fprintf(stderr,
6642163Skarels 			    "%s: too many mailer options\n", myname);
6742163Skarels 			exit(EX_USAGE);
6842163Skarels 		}
6942163Skarels 		*next_opt++ = *argv++;
7042163Skarels 		argc--;
7142163Skarels 	}
7242163Skarels 	*next_opt = NULL;
7342163Skarels 
7442162Skarels 	/* parse arguments */
7542163Skarels 	if (argc < 3)
7642162Skarels 	{
7742163Skarels 		fprintf(stderr,
7842163Skarels 		    "Usage: %s [-mailopts ...] listname ownername member...\n",
7942163Skarels 		    myname);
8042162Skarels 		exit(EX_USAGE);
8142162Skarels 	}
8242162Skarels 
8342162Skarels 	ml_name = *argv++;
8442162Skarels 	ml_owner = *argv++;
8542162Skarels 
8642162Skarels 	/* consume and discard leading "From_" line */
8742162Skarels 	while ((c = fgetc(stdin)) != EOF && c != '\n')
8842162Skarels 		continue;
8942162Skarels 
9042162Skarels 	/* open the connection to the mailer */
9151590Skarels 	mailfp = openmailer(ml_owner, next_opt - mailer_opts, mailer_opts,
9251590Skarels 	    argc, argv);
9342162Skarels 
9442162Skarels 	/* output the Resent-xxx: fields */
9542162Skarels 	fprintf(mailfp, "Resent-To:	%s\n", ml_name);
9642162Skarels 	fprintf(mailfp, "Resent-From:	%s\n", ml_owner);
9742164Skarels 	fprintf(mailfp, "Sender:	%s\n", ml_owner);
9842162Skarels 
9942162Skarels 	/*
10042162Skarels 	**  Consume header
10142162Skarels 	**
10242162Skarels 	**	Errors-To:	discard
10342162Skarels 	**	Precedence:	retain; mark that it has been seen
10442162Skarels 	**	Received:	discard
10542162Skarels 	**	Resent-*:	discard
10642162Skarels 	**	Return-Path:	discard
10742162Skarels 	**	Via:		discard
10842162Skarels 	**	X-Mailer:	discard
10942162Skarels 	**	others		retain
11042162Skarels 	*/
11142162Skarels 
11242162Skarels 	seen_precedence = FALSE;
11342162Skarels 
11442162Skarels 	while ((p = readheadertag(stdin)) != CHARNULL)
11542162Skarels 	{
11642162Skarels 		extern BOOL sameword();
11742162Skarels 
11842162Skarels 		mode = RETAIN;
11942162Skarels 		switch (p[0])
12042162Skarels 		{
12142162Skarels 		  case 'e':
12242162Skarels 		  case 'E':
12342162Skarels 			if (sameword(p, "errors-to", 10))
12442162Skarels 				mode = DISCARD;
12542162Skarels 			break;
12642162Skarels 
12742162Skarels 		  case 'p':
12842162Skarels 		  case 'P':
12942162Skarels 			if (sameword(p, "precedence", 11))
13042162Skarels 				seen_precedence = TRUE;
13142162Skarels 			break;
13242162Skarels 
13342162Skarels 		  case 'r':
13442162Skarels 		  case 'R':
13542162Skarels 			if (sameword(p, "return-path", 12) ||
13642164Skarels #ifdef notyet
13742162Skarels 			    sameword(p, "received", 9) ||
13842164Skarels #endif
13942162Skarels 			    sameword(p, "resent-", 7))
14042162Skarels 				mode = DISCARD;
14142162Skarels 			break;
14242162Skarels 
14342164Skarels 		  case 's':
14442164Skarels 		  case 'S':
14551590Skarels 			if (sameword(p, "sender", 7))
14642164Skarels 				mode = DISCARD;
14742164Skarels 			break;
14842164Skarels 
14942162Skarels 		  case 'v':
15042162Skarels 		  case 'V':
15142162Skarels 			if (sameword(p, "via", 4))
15242162Skarels 				mode = DISCARD;
15342162Skarels 			break;
15442162Skarels 
15542162Skarels 		  case 'x':
15642162Skarels 		  case 'X':
15742162Skarels 			if (sameword(p, "x-mailer", 9))
15842162Skarels 				mode = DISCARD;
15942162Skarels 			break;
16042162Skarels 		}
16142162Skarels 
16242162Skarels 		switch (mode)
16342162Skarels 		{
16442162Skarels 		  case RETAIN:
16542162Skarels 			fprintf(mailfp, "%s", p);
16642162Skarels 			copyheader(stdin, mailfp);
16742162Skarels 			break;
16842162Skarels 
16942162Skarels 		  case DISCARD:
17042162Skarels 			dropheader(stdin);
17142162Skarels 			break;
17242162Skarels 		}
17342162Skarels 	}
17442162Skarels 
17542162Skarels 	/* if no precedence was given, make it bulk mail */
17642162Skarels 	if (!seen_precedence)
17742163Skarels 		fprintf(mailfp, "Precedence: bulk\n");
17842162Skarels 
17942162Skarels 	/* copy the body of the message */
18042162Skarels 	copybody(stdin, mailfp);
18142162Skarels 
18242162Skarels 	/* clean up the connection */
18351590Skarels 	exit (my_pclose(mailfp));
18442162Skarels }
18542162Skarels 
18642162Skarels 
18742162Skarels 
18842162Skarels /*
18942162Skarels **  OPENMAILER -- open a connection to the mailer
19042162Skarels */
19142162Skarels 
19242162Skarels FILE *
openmailer(from,nopts,opts,argc,argv)19351590Skarels openmailer(from, nopts, opts, argc, argv)
19442163Skarels 	char *from;
19551590Skarels 	int nopts, argc;
19651590Skarels 	char **opts, **argv;
19742162Skarels {
19851590Skarels 	register char **argp;
19942162Skarels 	register FILE *mailfp;
20051590Skarels 	char **args;
20151590Skarels 	char *name;
20251590Skarels 	static char mailer[] = _PATH_SENDMAIL;
20342162Skarels 	extern int strlen();
20451590Skarels 	extern FILE *my_popen();
20551590Skarels 	extern char *malloc(), *rindex();
20642162Skarels 
20751590Skarels 	/*
20851590Skarels 	 * allocate space for argv; 4 args below, a null,
20951590Skarels 	 * and options and arguments from caller.
21051590Skarels 	 */
21151590Skarels 	args = (char **) malloc((nopts + argc + 5) * sizeof(char *));
21251590Skarels 	if (args == (char **) NULL)
21342163Skarels 	{
21451590Skarels 		fprintf(stderr,
21551590Skarels 		    "%s: arg list too long; can't allocate memory!?\n", myname);
21651590Skarels 		exit(EX_SOFTWARE);
21742163Skarels 	}
21851590Skarels 	argp = args;
21951590Skarels 	if ((name = rindex(mailer, '/')) != CHARNULL)
22051590Skarels 		name++;
22151590Skarels 	else
22251590Skarels 		name = mailer;
22351590Skarels 	*argp++ = name;
22451590Skarels 	*argp++ = "-f";
22551590Skarels 	*argp++ = from;
22651590Skarels 	*argp++ = "-oi";
22751590Skarels 	bcopy((char *) opts, (char *) argp, nopts * sizeof(*opts));
22851590Skarels 	argp += nopts;
22951590Skarels 	bcopy((char *) argv, (char *) argp, argc * sizeof(*argv));
23051590Skarels 	argp += argc;
23151590Skarels 	*argp = CHARNULL;
23251590Skarels 
233*55419Seric 	if (debug)
234*55419Seric 	{
23551590Skarels 		printf("| %s, args:\n", _PATH_SENDMAIL);
23651590Skarels 		for (argp = args; *argp; argp++)
23751590Skarels 			printf("  %s\n", *argp);
23851590Skarels 		printf("--------\n");
23951590Skarels 		return (stdout);
24042162Skarels 	}
24151590Skarels 	mailfp = my_popen(mailer, args, "w");
24242162Skarels 	if (mailfp == NULL)
24342162Skarels 	{
24442163Skarels 		fprintf(stderr, "%s: Unable to popen %s\n", myname,
24542163Skarels 		   _PATH_SENDMAIL);
24642162Skarels 		exit(EX_OSFILE);
24742162Skarels 	}
24842162Skarels 
24942162Skarels 	return (mailfp);
25042162Skarels }
25142162Skarels 
25242162Skarels 
25342162Skarels 
25442162Skarels /*
25542162Skarels **  DROPHEADER -- drop a single header field
25642162Skarels */
25742162Skarels 
25842162Skarels void
dropheader(infp)25942162Skarels dropheader(infp)
26042162Skarels 	register FILE *infp;
26142162Skarels {
26242162Skarels 	register int c;
26342162Skarels 
26442162Skarels 	while ((c = fgetc(infp)) != EOF)
26542162Skarels 	{
26642162Skarels 		if (c == '\n')
26742162Skarels 		{
26842162Skarels 			/* look at next character to check for continuation */
26942162Skarels 			c = fgetc(infp);
27042162Skarels 			if (c == ' ' || c == '\t')
27142162Skarels 				continue;
27242162Skarels 			if (c != EOF)
27342162Skarels 				ungetc(c, infp);
27442162Skarels 			break;
27542162Skarels 		}
27642162Skarels 	}
27742162Skarels }
27842162Skarels 
27942162Skarels 
28042162Skarels 
28142162Skarels /*
28242162Skarels **  COPYHEADER -- copy a single header field
28342162Skarels */
28442162Skarels 
28542162Skarels void
copyheader(infp,outfp)28642162Skarels copyheader(infp, outfp)
28742162Skarels 	register FILE *infp;
28842162Skarels 	register FILE *outfp;
28942162Skarels {
29042162Skarels 	register int c;
29142162Skarels 
29242162Skarels 	while ((c = fgetc(infp)) != EOF)
29342162Skarels 	{
29442162Skarels 		(void) fputc(c, outfp);
29542162Skarels 		if (c == '\n')
29642162Skarels 		{
29742162Skarels 			/* look at next character to check for continuation */
29842162Skarels 			c = fgetc(infp);
29942162Skarels 			if (c == ' ' || c == '\t')
30042162Skarels 			{
30142162Skarels 				(void) fputc(c, outfp);
30242162Skarels 				continue;
30342162Skarels 			}
30442162Skarels 			if (c != EOF)
30542162Skarels 				ungetc(c, infp);
30642162Skarels 			break;
30742162Skarels 		}
30842162Skarels 	}
30942162Skarels }
31042162Skarels 
31142162Skarels 
31242162Skarels 
31342162Skarels /*
31442162Skarels **  READHEADERTAG -- read and return the name of a header field
31542162Skarels */
31642162Skarels 
31742162Skarels #define MAXHDRTAG	60
31842162Skarels 
31942162Skarels char *
readheadertag(infp)32042162Skarels readheadertag(infp)
32142162Skarels 	register FILE *infp;
32242162Skarels {
32342162Skarels 	register int c;
32442162Skarels 	register char *bp;
32542162Skarels 	int i;
32642162Skarels 	static char buf[MAXHDRTAG + 1];
32742162Skarels 	extern char *strchr();
32842162Skarels 
32942162Skarels 	c = fgetc(infp);
33042162Skarels 	if (c == EOF)
33142162Skarels 		return (CHARNULL);
33242162Skarels 	if (c == '\n')
33342162Skarels 	{
33442162Skarels 		ungetc(c, infp);
33542162Skarels 		return (CHARNULL);
33642162Skarels 	}
33742162Skarels 
33842162Skarels 	bp = buf;
33942162Skarels 	i = sizeof buf;
34042162Skarels 	do
34142162Skarels 	{
34242162Skarels 		*bp++ = c;
34342162Skarels 		c = fgetc(infp);
34442162Skarels 	} while (--i > 0 && c != EOF && c != '\0' &&
34542162Skarels 		 strchr(" \t\n:", c) == CHARNULL);
34642162Skarels 	if (c != EOF)
34742162Skarels 		ungetc(c, infp);
34842162Skarels 	*bp++ = '\0';
34942162Skarels 	return (buf);
35042162Skarels }
35142162Skarels 
35242162Skarels 
35342162Skarels 
35442162Skarels /*
35542162Skarels **  COPYBODY -- copy the body of a message
35642162Skarels */
35742162Skarels 
35842162Skarels void
copybody(infp,outfp)35942162Skarels copybody(infp, outfp)
36042162Skarels 	register FILE *infp;
36142162Skarels 	register FILE *outfp;
36242162Skarels {
36342162Skarels 	register int c;
36442162Skarels 
36542162Skarels 	while ((c = fgetc(infp)) != EOF)
36642162Skarels 		fputc(c, outfp);
36742162Skarels }
36842162Skarels 
36942162Skarels 
37042162Skarels 
37142162Skarels /*
37242162Skarels **  SAMEWORD -- return true if two words are identical.  The first
37342162Skarels **		word is case insignificant; the second must be lower case.
37442162Skarels */
37542162Skarels 
37642162Skarels BOOL
sameword(test,pat,len)37742162Skarels sameword(test, pat, len)
37842162Skarels 	register char *test;
37942162Skarels 	register char *pat;
38042162Skarels 	int len;
38142162Skarels {
38242162Skarels 	for (; --len >= 0; test++, pat++)
38342162Skarels 	{
38442162Skarels 		if (*test == *pat)
38542162Skarels 			continue;
38642162Skarels 		if (isupper(*test) && tolower(*test) == *pat)
38742162Skarels 			continue;
38842162Skarels 		return (FALSE);
38942162Skarels 	}
39042162Skarels 	return (TRUE);
39142162Skarels }
39251590Skarels 
39351590Skarels 
39451590Skarels 
39551590Skarels /*
39651590Skarels  * from libc popen:
39751590Skarels static char sccsid[] = "@(#)popen.c	5.12 (Berkeley) 4/6/90";
39851590Skarels  *
39951590Skarels  * This code is derived from software written by Ken Arnold and
40051590Skarels  * published in UNIX Review, Vol. 6, No. 8.
40151590Skarels  *
40251590Skarels  * modified to avoid sh, be safe for setuid/setgid programs,
40351590Skarels  * and simplified to support only one popen'ed stream.
40451590Skarels  */
40551590Skarels 
40651590Skarels 
40751590Skarels #include <sys/signal.h>
40851590Skarels #include <sys/wait.h>
40951590Skarels #include <errno.h>
41051590Skarels #include <unistd.h>
41151590Skarels /*
41251590Skarels #include <stdio.h>
41351590Skarels #include <paths.h>
41451590Skarels */
41551590Skarels 
41651590Skarels static pid_t pid;
41751590Skarels 
41851590Skarels FILE *
my_popen(program,args,type)41951590Skarels my_popen(program, args, type)
42051590Skarels 	char *program, *type;
42151590Skarels 	char **args;
42251590Skarels {
42351590Skarels 	FILE *iop;
42451590Skarels 	int pdes[2];
42551590Skarels 	char *malloc();
42651590Skarels 
42751590Skarels 	if (*type != 'r' && *type != 'w' || type[1])
42851590Skarels 		return(NULL);
42951590Skarels 
43051590Skarels 	if (pipe(pdes) < 0)
43151590Skarels 		return(NULL);
43251590Skarels 	switch (pid = vfork()) {
43351590Skarels 	case -1:			/* error */
43451590Skarels 		(void)close(pdes[0]);
43551590Skarels 		(void)close(pdes[1]);
43651590Skarels 		return(NULL);
43751590Skarels 		/* NOTREACHED */
43851590Skarels 	case 0:				/* child */
43951590Skarels 		if (*type == 'r') {
44051590Skarels 			if (pdes[1] != STDOUT_FILENO) {
44151590Skarels 				(void)dup2(pdes[1], STDOUT_FILENO);
44251590Skarels 				(void)close(pdes[1]);
44351590Skarels 			}
44451590Skarels 			(void)close(pdes[0]);
44551590Skarels 		} else {
44651590Skarels 			if (pdes[0] != STDIN_FILENO) {
44751590Skarels 				(void)dup2(pdes[0], STDIN_FILENO);
44851590Skarels 				(void)close(pdes[0]);
44951590Skarels 			}
45051590Skarels 			(void)close(pdes[1]);
45151590Skarels 		}
45251590Skarels 		execv(program, args);
45351590Skarels 		_exit(127);
45451590Skarels 		/* NOTREACHED */
45551590Skarels 	}
45651590Skarels 	/* parent; assume fdopen can't fail...  */
45751590Skarels 	if (*type == 'r') {
45851590Skarels 		iop = fdopen(pdes[0], type);
45951590Skarels 		(void)close(pdes[1]);
46051590Skarels 	} else {
46151590Skarels 		iop = fdopen(pdes[1], type);
46251590Skarels 		(void)close(pdes[0]);
46351590Skarels 	}
46451590Skarels 	return (iop);
46551590Skarels }
46651590Skarels 
my_pclose(iop)46751590Skarels my_pclose(iop)
46851590Skarels 	FILE *iop;
46951590Skarels {
47051590Skarels 	extern int errno;
47151590Skarels 	register int fdes;
47251590Skarels 	int omask;
47351590Skarels 	int pstat;
47451823Skarels 	pid_t wpid;
47551590Skarels 
47651590Skarels 	(void)fclose(iop);
47751590Skarels 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
47851590Skarels 	do {
47951590Skarels 		wpid = waitpid(pid, &pstat, 0);
48051590Skarels 	} while (wpid == -1 && errno == EINTR);
48151590Skarels 	(void)sigsetmask(omask);
48251590Skarels 	pid = 0;
48351590Skarels 	return (pid == -1 ? -1 : pstat);
48451590Skarels }
485