1 /*
2 * Copyright (c) 1992 Eric P. Allman
3 * Copyright (c) 1992 Regents of the University of California.
4 * All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9 #ifndef lint
10 char copyright[] =
11 "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
12 All rights reserved.\n";
13 static char sccsid[] = "@(#)mldistrib.c 5.6 (Berkeley) 07/20/92";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <sysexits.h>
20 #include <paths.h>
21
22 #define TRUE 1
23 #define FALSE 0
24 typedef char BOOL;
25
26 #define CHARNULL ((char *) NULL)
27 #define MAXMAILOPTS 20
28
29 enum copymode {RETAIN, DISCARD};
30 char *myname;
31 int debug;
32
main(argc,argv)33 main(argc, argv)
34 int argc;
35 char **argv;
36 {
37 BOOL seen_precedence;
38 register FILE *mailfp;
39 enum copymode mode;
40 register char *p;
41 char *ml_name;
42 char *ml_owner;
43 char *mailer_opts[MAXMAILOPTS+1];
44 char **next_opt = mailer_opts;
45 char c;
46 extern FILE *openmailer();
47 extern char *readheadertag();
48 extern void copyheader();
49 extern void dropheader();
50 extern void copybody();
51
52 myname = argv[0];
53 argc--, argv++;
54 while (*argv[0] == '-')
55 {
56 if (strcmp(argv[0], "-d") == 0)
57 {
58 debug++;
59 argv++;
60 argc--;
61 continue;
62 }
63 if (next_opt >= &mailer_opts[MAXMAILOPTS])
64 {
65 fprintf(stderr,
66 "%s: too many mailer options\n", myname);
67 exit(EX_USAGE);
68 }
69 *next_opt++ = *argv++;
70 argc--;
71 }
72 *next_opt = NULL;
73
74 /* parse arguments */
75 if (argc < 3)
76 {
77 fprintf(stderr,
78 "Usage: %s [-mailopts ...] listname ownername member...\n",
79 myname);
80 exit(EX_USAGE);
81 }
82
83 ml_name = *argv++;
84 ml_owner = *argv++;
85
86 /* consume and discard leading "From_" line */
87 while ((c = fgetc(stdin)) != EOF && c != '\n')
88 continue;
89
90 /* open the connection to the mailer */
91 mailfp = openmailer(ml_owner, next_opt - mailer_opts, mailer_opts,
92 argc, argv);
93
94 /* output the Resent-xxx: fields */
95 fprintf(mailfp, "Resent-To: %s\n", ml_name);
96 fprintf(mailfp, "Resent-From: %s\n", ml_owner);
97 fprintf(mailfp, "Sender: %s\n", ml_owner);
98
99 /*
100 ** Consume header
101 **
102 ** Errors-To: discard
103 ** Precedence: retain; mark that it has been seen
104 ** Received: discard
105 ** Resent-*: discard
106 ** Return-Path: discard
107 ** Via: discard
108 ** X-Mailer: discard
109 ** others retain
110 */
111
112 seen_precedence = FALSE;
113
114 while ((p = readheadertag(stdin)) != CHARNULL)
115 {
116 extern BOOL sameword();
117
118 mode = RETAIN;
119 switch (p[0])
120 {
121 case 'e':
122 case 'E':
123 if (sameword(p, "errors-to", 10))
124 mode = DISCARD;
125 break;
126
127 case 'p':
128 case 'P':
129 if (sameword(p, "precedence", 11))
130 seen_precedence = TRUE;
131 break;
132
133 case 'r':
134 case 'R':
135 if (sameword(p, "return-path", 12) ||
136 #ifdef notyet
137 sameword(p, "received", 9) ||
138 #endif
139 sameword(p, "resent-", 7))
140 mode = DISCARD;
141 break;
142
143 case 's':
144 case 'S':
145 if (sameword(p, "sender", 7))
146 mode = DISCARD;
147 break;
148
149 case 'v':
150 case 'V':
151 if (sameword(p, "via", 4))
152 mode = DISCARD;
153 break;
154
155 case 'x':
156 case 'X':
157 if (sameword(p, "x-mailer", 9))
158 mode = DISCARD;
159 break;
160 }
161
162 switch (mode)
163 {
164 case RETAIN:
165 fprintf(mailfp, "%s", p);
166 copyheader(stdin, mailfp);
167 break;
168
169 case DISCARD:
170 dropheader(stdin);
171 break;
172 }
173 }
174
175 /* if no precedence was given, make it bulk mail */
176 if (!seen_precedence)
177 fprintf(mailfp, "Precedence: bulk\n");
178
179 /* copy the body of the message */
180 copybody(stdin, mailfp);
181
182 /* clean up the connection */
183 exit (my_pclose(mailfp));
184 }
185
186
187
188 /*
189 ** OPENMAILER -- open a connection to the mailer
190 */
191
192 FILE *
openmailer(from,nopts,opts,argc,argv)193 openmailer(from, nopts, opts, argc, argv)
194 char *from;
195 int nopts, argc;
196 char **opts, **argv;
197 {
198 register char **argp;
199 register FILE *mailfp;
200 char **args;
201 char *name;
202 static char mailer[] = _PATH_SENDMAIL;
203 extern int strlen();
204 extern FILE *my_popen();
205 extern char *malloc(), *rindex();
206
207 /*
208 * allocate space for argv; 4 args below, a null,
209 * and options and arguments from caller.
210 */
211 args = (char **) malloc((nopts + argc + 5) * sizeof(char *));
212 if (args == (char **) NULL)
213 {
214 fprintf(stderr,
215 "%s: arg list too long; can't allocate memory!?\n", myname);
216 exit(EX_SOFTWARE);
217 }
218 argp = args;
219 if ((name = rindex(mailer, '/')) != CHARNULL)
220 name++;
221 else
222 name = mailer;
223 *argp++ = name;
224 *argp++ = "-f";
225 *argp++ = from;
226 *argp++ = "-oi";
227 bcopy((char *) opts, (char *) argp, nopts * sizeof(*opts));
228 argp += nopts;
229 bcopy((char *) argv, (char *) argp, argc * sizeof(*argv));
230 argp += argc;
231 *argp = CHARNULL;
232
233 if (debug)
234 {
235 printf("| %s, args:\n", _PATH_SENDMAIL);
236 for (argp = args; *argp; argp++)
237 printf(" %s\n", *argp);
238 printf("--------\n");
239 return (stdout);
240 }
241 mailfp = my_popen(mailer, args, "w");
242 if (mailfp == NULL)
243 {
244 fprintf(stderr, "%s: Unable to popen %s\n", myname,
245 _PATH_SENDMAIL);
246 exit(EX_OSFILE);
247 }
248
249 return (mailfp);
250 }
251
252
253
254 /*
255 ** DROPHEADER -- drop a single header field
256 */
257
258 void
dropheader(infp)259 dropheader(infp)
260 register FILE *infp;
261 {
262 register int c;
263
264 while ((c = fgetc(infp)) != EOF)
265 {
266 if (c == '\n')
267 {
268 /* look at next character to check for continuation */
269 c = fgetc(infp);
270 if (c == ' ' || c == '\t')
271 continue;
272 if (c != EOF)
273 ungetc(c, infp);
274 break;
275 }
276 }
277 }
278
279
280
281 /*
282 ** COPYHEADER -- copy a single header field
283 */
284
285 void
copyheader(infp,outfp)286 copyheader(infp, outfp)
287 register FILE *infp;
288 register FILE *outfp;
289 {
290 register int c;
291
292 while ((c = fgetc(infp)) != EOF)
293 {
294 (void) fputc(c, outfp);
295 if (c == '\n')
296 {
297 /* look at next character to check for continuation */
298 c = fgetc(infp);
299 if (c == ' ' || c == '\t')
300 {
301 (void) fputc(c, outfp);
302 continue;
303 }
304 if (c != EOF)
305 ungetc(c, infp);
306 break;
307 }
308 }
309 }
310
311
312
313 /*
314 ** READHEADERTAG -- read and return the name of a header field
315 */
316
317 #define MAXHDRTAG 60
318
319 char *
readheadertag(infp)320 readheadertag(infp)
321 register FILE *infp;
322 {
323 register int c;
324 register char *bp;
325 int i;
326 static char buf[MAXHDRTAG + 1];
327 extern char *strchr();
328
329 c = fgetc(infp);
330 if (c == EOF)
331 return (CHARNULL);
332 if (c == '\n')
333 {
334 ungetc(c, infp);
335 return (CHARNULL);
336 }
337
338 bp = buf;
339 i = sizeof buf;
340 do
341 {
342 *bp++ = c;
343 c = fgetc(infp);
344 } while (--i > 0 && c != EOF && c != '\0' &&
345 strchr(" \t\n:", c) == CHARNULL);
346 if (c != EOF)
347 ungetc(c, infp);
348 *bp++ = '\0';
349 return (buf);
350 }
351
352
353
354 /*
355 ** COPYBODY -- copy the body of a message
356 */
357
358 void
copybody(infp,outfp)359 copybody(infp, outfp)
360 register FILE *infp;
361 register FILE *outfp;
362 {
363 register int c;
364
365 while ((c = fgetc(infp)) != EOF)
366 fputc(c, outfp);
367 }
368
369
370
371 /*
372 ** SAMEWORD -- return true if two words are identical. The first
373 ** word is case insignificant; the second must be lower case.
374 */
375
376 BOOL
sameword(test,pat,len)377 sameword(test, pat, len)
378 register char *test;
379 register char *pat;
380 int len;
381 {
382 for (; --len >= 0; test++, pat++)
383 {
384 if (*test == *pat)
385 continue;
386 if (isupper(*test) && tolower(*test) == *pat)
387 continue;
388 return (FALSE);
389 }
390 return (TRUE);
391 }
392
393
394
395 /*
396 * from libc popen:
397 static char sccsid[] = "@(#)popen.c 5.12 (Berkeley) 4/6/90";
398 *
399 * This code is derived from software written by Ken Arnold and
400 * published in UNIX Review, Vol. 6, No. 8.
401 *
402 * modified to avoid sh, be safe for setuid/setgid programs,
403 * and simplified to support only one popen'ed stream.
404 */
405
406
407 #include <sys/signal.h>
408 #include <sys/wait.h>
409 #include <errno.h>
410 #include <unistd.h>
411 /*
412 #include <stdio.h>
413 #include <paths.h>
414 */
415
416 static pid_t pid;
417
418 FILE *
my_popen(program,args,type)419 my_popen(program, args, type)
420 char *program, *type;
421 char **args;
422 {
423 FILE *iop;
424 int pdes[2];
425 char *malloc();
426
427 if (*type != 'r' && *type != 'w' || type[1])
428 return(NULL);
429
430 if (pipe(pdes) < 0)
431 return(NULL);
432 switch (pid = vfork()) {
433 case -1: /* error */
434 (void)close(pdes[0]);
435 (void)close(pdes[1]);
436 return(NULL);
437 /* NOTREACHED */
438 case 0: /* child */
439 if (*type == 'r') {
440 if (pdes[1] != STDOUT_FILENO) {
441 (void)dup2(pdes[1], STDOUT_FILENO);
442 (void)close(pdes[1]);
443 }
444 (void)close(pdes[0]);
445 } else {
446 if (pdes[0] != STDIN_FILENO) {
447 (void)dup2(pdes[0], STDIN_FILENO);
448 (void)close(pdes[0]);
449 }
450 (void)close(pdes[1]);
451 }
452 execv(program, args);
453 _exit(127);
454 /* NOTREACHED */
455 }
456 /* parent; assume fdopen can't fail... */
457 if (*type == 'r') {
458 iop = fdopen(pdes[0], type);
459 (void)close(pdes[1]);
460 } else {
461 iop = fdopen(pdes[1], type);
462 (void)close(pdes[0]);
463 }
464 return (iop);
465 }
466
my_pclose(iop)467 my_pclose(iop)
468 FILE *iop;
469 {
470 extern int errno;
471 register int fdes;
472 int omask;
473 int pstat;
474 pid_t wpid;
475
476 (void)fclose(iop);
477 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
478 do {
479 wpid = waitpid(pid, &pstat, 0);
480 } while (wpid == -1 && errno == EINTR);
481 (void)sigsetmask(omask);
482 pid = 0;
483 return (pid == -1 ? -1 : pstat);
484 }
485