1 #include <stdio.h> 2 #include <ctype.h> 3 #include <sysexits.h> 4 #include <paths.h> 5 6 #define TRUE 1 7 #define FALSE 0 8 typedef char BOOL; 9 10 #define CHARNULL ((char *) NULL) 11 #define MAXMAILOPTS 20 12 13 enum copymode {RETAIN, DISCARD}; 14 char *myname; 15 16 main(argc, argv) 17 int argc; 18 char **argv; 19 { 20 BOOL seen_precedence; 21 register FILE *mailfp; 22 enum copymode mode; 23 register char *p; 24 char *ml_name; 25 char *ml_owner; 26 char *mailer_opts[MAXMAILOPTS+1]; 27 char **next_opt = mailer_opts; 28 char c; 29 extern FILE *openmailer(); 30 extern char *readheadertag(); 31 extern void copyheader(); 32 extern void dropheader(); 33 extern void copybody(); 34 35 myname = argv[0]; 36 argc--, argv++; 37 while (*argv[0] == '-') 38 { 39 if (next_opt >= &mailer_opts[MAXMAILOPTS]) 40 { 41 fprintf(stderr, 42 "%s: too many mailer options\n", myname); 43 exit(EX_USAGE); 44 } 45 *next_opt++ = *argv++; 46 argc--; 47 } 48 *next_opt = NULL; 49 50 /* parse arguments */ 51 if (argc < 3) 52 { 53 fprintf(stderr, 54 "Usage: %s [-mailopts ...] listname ownername member...\n", 55 myname); 56 exit(EX_USAGE); 57 } 58 59 ml_name = *argv++; 60 ml_owner = *argv++; 61 62 /* consume and discard leading "From_" line */ 63 while ((c = fgetc(stdin)) != EOF && c != '\n') 64 continue; 65 66 /* open the connection to the mailer */ 67 mailfp = openmailer(ml_owner, mailer_opts, argv); 68 69 /* output the Resent-xxx: fields */ 70 fprintf(mailfp, "Resent-To: %s\n", ml_name); 71 fprintf(mailfp, "Resent-From: %s\n", ml_owner); 72 fprintf(mailfp, "Sender: %s\n", ml_owner); 73 74 /* 75 ** Consume header 76 ** 77 ** Errors-To: discard 78 ** Precedence: retain; mark that it has been seen 79 ** Received: discard 80 ** Resent-*: discard 81 ** Return-Path: discard 82 ** Via: discard 83 ** X-Mailer: discard 84 ** others retain 85 */ 86 87 seen_precedence = FALSE; 88 89 while ((p = readheadertag(stdin)) != CHARNULL) 90 { 91 extern BOOL sameword(); 92 93 mode = RETAIN; 94 switch (p[0]) 95 { 96 case 'e': 97 case 'E': 98 if (sameword(p, "errors-to", 10)) 99 mode = DISCARD; 100 break; 101 102 case 'p': 103 case 'P': 104 if (sameword(p, "precedence", 11)) 105 seen_precedence = TRUE; 106 break; 107 108 case 'r': 109 case 'R': 110 if (sameword(p, "return-path", 12) || 111 #ifdef notyet 112 sameword(p, "received", 9) || 113 #endif 114 sameword(p, "resent-", 7)) 115 mode = DISCARD; 116 break; 117 118 case 's': 119 case 'S': 120 if sameword(p, "sender", 7)) 121 mode = DISCARD; 122 break; 123 124 case 'v': 125 case 'V': 126 if (sameword(p, "via", 4)) 127 mode = DISCARD; 128 break; 129 130 case 'x': 131 case 'X': 132 if (sameword(p, "x-mailer", 9)) 133 mode = DISCARD; 134 break; 135 } 136 137 switch (mode) 138 { 139 case RETAIN: 140 fprintf(mailfp, "%s", p); 141 copyheader(stdin, mailfp); 142 break; 143 144 case DISCARD: 145 dropheader(stdin); 146 break; 147 } 148 } 149 150 /* if no precedence was given, make it bulk mail */ 151 if (!seen_precedence) 152 fprintf(mailfp, "Precedence: bulk\n"); 153 154 /* copy the body of the message */ 155 copybody(stdin, mailfp); 156 157 /* clean up the connection */ 158 exit (pclose(mailfp)); 159 } 160 161 162 163 /* 164 ** OPENMAILER -- open a connection to the mailer 165 */ 166 167 FILE * 168 openmailer(from, opt, argv) 169 char *from; 170 char **opt, **argv; 171 { 172 register char *bp; 173 register FILE *mailfp; 174 char buf[10000]; 175 extern int strlen(); 176 177 bp = buf; 178 (void) sprintf(bp, "%s -f %s -oi", _PATH_SENDMAIL, from); 179 bp += strlen(bp); 180 181 while (*opt != CHARNULL) 182 { 183 (void) sprintf(bp, " %s", *opt++); 184 bp += strlen(bp); 185 if (bp >= buf + sizeof(buf)) { 186 fprintf(stderr, "%s: options list too long\n", myname); 187 exit(EX_SOFTWARE); 188 } 189 } 190 while (*argv != CHARNULL) 191 { 192 (void) sprintf(bp, " %s", *argv++); 193 bp += strlen(bp); 194 if (bp >= buf + sizeof(buf)) { 195 fprintf(stderr, "%s: arg list too long\n", myname); 196 exit(EX_SOFTWARE); 197 } 198 } 199 200 mailfp = popen(buf, "w"); 201 if (mailfp == NULL) 202 { 203 fprintf(stderr, "%s: Unable to popen %s\n", myname, 204 _PATH_SENDMAIL); 205 exit(EX_OSFILE); 206 } 207 208 return (mailfp); 209 } 210 211 212 213 /* 214 ** DROPHEADER -- drop a single header field 215 */ 216 217 void 218 dropheader(infp) 219 register FILE *infp; 220 { 221 register int c; 222 223 while ((c = fgetc(infp)) != EOF) 224 { 225 if (c == '\n') 226 { 227 /* look at next character to check for continuation */ 228 c = fgetc(infp); 229 if (c == ' ' || c == '\t') 230 continue; 231 if (c != EOF) 232 ungetc(c, infp); 233 break; 234 } 235 } 236 } 237 238 239 240 /* 241 ** COPYHEADER -- copy a single header field 242 */ 243 244 void 245 copyheader(infp, outfp) 246 register FILE *infp; 247 register FILE *outfp; 248 { 249 register int c; 250 251 while ((c = fgetc(infp)) != EOF) 252 { 253 (void) fputc(c, outfp); 254 if (c == '\n') 255 { 256 /* look at next character to check for continuation */ 257 c = fgetc(infp); 258 if (c == ' ' || c == '\t') 259 { 260 (void) fputc(c, outfp); 261 continue; 262 } 263 if (c != EOF) 264 ungetc(c, infp); 265 break; 266 } 267 } 268 } 269 270 271 272 /* 273 ** READHEADERTAG -- read and return the name of a header field 274 */ 275 276 #define MAXHDRTAG 60 277 278 char * 279 readheadertag(infp) 280 register FILE *infp; 281 { 282 register int c; 283 register char *bp; 284 int i; 285 static char buf[MAXHDRTAG + 1]; 286 extern char *strchr(); 287 288 c = fgetc(infp); 289 if (c == EOF) 290 return (CHARNULL); 291 if (c == '\n') 292 { 293 ungetc(c, infp); 294 return (CHARNULL); 295 } 296 297 bp = buf; 298 i = sizeof buf; 299 do 300 { 301 *bp++ = c; 302 c = fgetc(infp); 303 } while (--i > 0 && c != EOF && c != '\0' && 304 strchr(" \t\n:", c) == CHARNULL); 305 if (c != EOF) 306 ungetc(c, infp); 307 *bp++ = '\0'; 308 return (buf); 309 } 310 311 312 313 /* 314 ** COPYBODY -- copy the body of a message 315 */ 316 317 void 318 copybody(infp, outfp) 319 register FILE *infp; 320 register FILE *outfp; 321 { 322 register int c; 323 324 while ((c = fgetc(infp)) != EOF) 325 fputc(c, outfp); 326 } 327 328 329 330 /* 331 ** SAMEWORD -- return true if two words are identical. The first 332 ** word is case insignificant; the second must be lower case. 333 */ 334 335 BOOL 336 sameword(test, pat, len) 337 register char *test; 338 register char *pat; 339 int len; 340 { 341 for (; --len >= 0; test++, pat++) 342 { 343 if (*test == *pat) 344 continue; 345 if (isupper(*test) && tolower(*test) == *pat) 346 continue; 347 return (FALSE); 348 } 349 return (TRUE); 350 } 351