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 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 * 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 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 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 * 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 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 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 * 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 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