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