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