1 # include <errno.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)headers.c 3.41 12/13/82); 5 6 /* 7 ** CHOMPHEADER -- process and save a header line. 8 ** 9 ** Called by collect and by readcf to deal with header lines. 10 ** 11 ** Parameters: 12 ** line -- header as a text line. 13 ** def -- if set, this is a default value. 14 ** 15 ** Returns: 16 ** flags for this header. 17 ** 18 ** Side Effects: 19 ** The header is saved on the header list. 20 ** Contents of 'line' are destroyed. 21 */ 22 23 chompheader(line, def) 24 char *line; 25 bool def; 26 { 27 register char *p; 28 register HDR *h; 29 HDR **hp; 30 char *fname; 31 char *fvalue; 32 struct hdrinfo *hi; 33 bool cond = FALSE; 34 u_long mopts; 35 extern u_long mfencode(); 36 extern char *crackaddr(); 37 38 # ifdef DEBUG 39 if (tTd(31, 6)) 40 printf("chompheader: %s\n", line); 41 # endif DEBUG 42 43 /* strip off options */ 44 mopts = 0; 45 p = line; 46 if (*p == '?') 47 { 48 /* have some */ 49 register char *q = index(p + 1, *p); 50 51 if (q != NULL) 52 { 53 *q++ = '\0'; 54 mopts = mfencode(p + 1); 55 p = q; 56 } 57 else 58 syserr("chompheader: syntax error, line \"%s\"", line); 59 cond = TRUE; 60 } 61 62 /* find canonical name */ 63 fname = p; 64 p = index(p, ':'); 65 fvalue = &p[1]; 66 while (isspace(*--p)) 67 continue; 68 *++p = '\0'; 69 makelower(fname); 70 71 /* strip field value on front */ 72 if (*fvalue == ' ') 73 fvalue++; 74 75 /* search header list for this header */ 76 for (hp = &CurEnv->e_header, h = CurEnv->e_header; h != NULL; 77 hp = &h->h_link, h = h->h_link) 78 { 79 if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 80 break; 81 } 82 83 /* see if it is a known type */ 84 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 85 { 86 if (strcmp(hi->hi_field, fname) == 0) 87 break; 88 } 89 90 /* if this means "end of header" quit now */ 91 if (bitset(H_EOH, hi->hi_flags)) 92 return (hi->hi_flags); 93 94 /* create/fill in a new node */ 95 if (h == NULL || bitset(H_FORCE, h->h_flags)) 96 { 97 /* create a new node */ 98 h = (HDR *) xalloc(sizeof *h); 99 h->h_field = newstr(fname); 100 h->h_value = NULL; 101 h->h_link = *hp; 102 h->h_mflags = mopts; 103 *hp = h; 104 } 105 h->h_flags = hi->hi_flags; 106 if (def) 107 h->h_flags |= H_DEFAULT; 108 if (cond) 109 h->h_flags |= H_CHECK; 110 if (h->h_value != NULL) 111 free((char *) h->h_value); 112 h->h_value = newstr(fvalue); 113 114 /* hack to see if this is a new format message */ 115 if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 116 (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 117 index(fvalue, '<') != NULL || index(fvalue, ';') != NULL)) 118 { 119 CurEnv->e_flags &= ~EF_OLDSTYLE; 120 } 121 122 /* send to this person if we so desire */ 123 if (!def && GrabTo && bitset(H_RCPT, h->h_flags)) 124 sendtolist(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 125 126 return (h->h_flags); 127 } 128 /* 129 ** ADDHEADER -- add a header entry to the end of the queue. 130 ** 131 ** This bypasses the special checking of chompheader. 132 ** 133 ** Parameters: 134 ** field -- the name of the header field. 135 ** value -- the value of the field. It must be lower-cased. 136 ** e -- the envelope to add them to. 137 ** 138 ** Returns: 139 ** none. 140 ** 141 ** Side Effects: 142 ** adds the field on the list of headers for this envelope. 143 */ 144 145 addheader(field, value, e) 146 char *field; 147 char *value; 148 ENVELOPE *e; 149 { 150 register HDR *h; 151 register struct hdrinfo *hi; 152 HDR **hp; 153 154 /* find info struct */ 155 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 156 { 157 if (strcmp(field, hi->hi_field) == 0) 158 break; 159 } 160 161 /* find current place in list -- keep back pointer? */ 162 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 163 { 164 if (strcmp(field, h->h_field) == 0) 165 break; 166 } 167 168 /* allocate space for new header */ 169 h = (HDR *) xalloc(sizeof *h); 170 h->h_field = field; 171 h->h_value = newstr(value); 172 h->h_link = *hp; 173 h->h_flags = hi->hi_flags | H_DEFAULT; 174 h->h_mflags = 0; 175 *hp = h; 176 } 177 /* 178 ** HVALUE -- return value of a header. 179 ** 180 ** Only "real" fields (i.e., ones that have not been supplied 181 ** as a default) are used. 182 ** 183 ** Parameters: 184 ** field -- the field name. 185 ** 186 ** Returns: 187 ** pointer to the value part. 188 ** NULL if not found. 189 ** 190 ** Side Effects: 191 ** none. 192 */ 193 194 char * 195 hvalue(field) 196 char *field; 197 { 198 register HDR *h; 199 200 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 201 { 202 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 203 return (h->h_value); 204 } 205 return (NULL); 206 } 207 /* 208 ** ISHEADER -- predicate telling if argument is a header. 209 ** 210 ** A line is a header if it has a single word followed by 211 ** optional white space followed by a colon. 212 ** 213 ** Parameters: 214 ** s -- string to check for possible headerness. 215 ** 216 ** Returns: 217 ** TRUE if s is a header. 218 ** FALSE otherwise. 219 ** 220 ** Side Effects: 221 ** none. 222 */ 223 224 bool 225 isheader(s) 226 register char *s; 227 { 228 while (*s > ' ' && *s != ':' && *s != '\0') 229 s++; 230 231 /* following technically violates RFC822 */ 232 while (isspace(*s)) 233 s++; 234 235 return (*s == ':'); 236 } 237 /* 238 ** EATHEADER -- run through the stored header and extract info. 239 ** 240 ** Parameters: 241 ** e -- the envelope to process. 242 ** 243 ** Returns: 244 ** none. 245 ** 246 ** Side Effects: 247 ** Sets a bunch of global variables from information 248 ** in the collected header. 249 ** Aborts the message if the hop count is exceeded. 250 */ 251 252 eatheader(e) 253 register ENVELOPE *e; 254 { 255 register HDR *h; 256 register char *p; 257 int hopcnt = 0; 258 259 #ifdef DEBUG 260 if (tTd(32, 1)) 261 printf("----- collected header -----\n"); 262 #endif DEBUG 263 for (h = e->e_header; h != NULL; h = h->h_link) 264 { 265 #ifdef DEBUG 266 extern char *capitalize(); 267 268 if (tTd(32, 1)) 269 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 270 #endif DEBUG 271 if (bitset(H_TRACE, h->h_flags)) 272 hopcnt++; 273 } 274 #ifdef DEBUG 275 if (tTd(32, 1)) 276 printf("----------------------------\n"); 277 #endif DEBUG 278 279 /* store hop count */ 280 if (hopcnt > e->e_hopcount) 281 e->e_hopcount = hopcnt; 282 283 /* message priority */ 284 p = hvalue("precedence"); 285 if (p != NULL) 286 e->e_class = priencode(p); 287 if (!QueueRun) 288 e->e_msgpriority = e->e_msgsize - e->e_class * WKPRIFACT; 289 290 /* return receipt to */ 291 p = hvalue("return-receipt-to"); 292 if (p != NULL) 293 e->e_receiptto = p; 294 295 /* errors to */ 296 p = hvalue("errors-to"); 297 if (p != NULL) 298 sendtolist(p, (ADDRESS *) NULL, &e->e_errorqueue); 299 300 /* from person */ 301 if (OpMode == MD_ARPAFTP) 302 { 303 register struct hdrinfo *hi = HdrInfo; 304 305 for (p = NULL; p == NULL && hi->hi_field != NULL; hi++) 306 { 307 if (bitset(H_FROM, hi->hi_flags)) 308 p = hvalue(hi->hi_field); 309 } 310 if (p != NULL) 311 setsender(p); 312 } 313 314 /* full name of from person */ 315 p = hvalue("full-name"); 316 if (p != NULL) 317 define('x', p, e); 318 319 /* date message originated */ 320 p = hvalue("posted-date"); 321 if (p == NULL) 322 p = hvalue("date"); 323 if (p != NULL) 324 { 325 define('a', p, e); 326 /* we don't have a good way to do canonical conversion .... 327 define('d', newstr(arpatounix(p)), e); 328 .... so we will ignore the problem for the time being */ 329 } 330 } 331 /* 332 ** PRIENCODE -- encode external priority names into internal values. 333 ** 334 ** Parameters: 335 ** p -- priority in ascii. 336 ** 337 ** Returns: 338 ** priority as a numeric level. 339 ** 340 ** Side Effects: 341 ** none. 342 */ 343 344 priencode(p) 345 char *p; 346 { 347 register int i; 348 extern bool sameword(); 349 350 for (i = 0; i < NumPriorities; i++) 351 { 352 if (sameword(p, Priorities[i].pri_name)) 353 return (Priorities[i].pri_val); 354 } 355 356 /* unknown priority */ 357 return (0); 358 } 359 /* 360 ** CRACKADDR -- parse an address and turn it into a macro 361 ** 362 ** This doesn't actually parse the address -- it just extracts 363 ** it and replaces it with "$g". The parse is totally ad hoc 364 ** and isn't even guaranteed to leave something syntactically 365 ** identical to what it started with. However, it does leave 366 ** something semantically identical. 367 ** 368 ** The process is kind of strange. There are a number of 369 ** interesting cases: 370 ** 1. comment <address> comment ==> comment <$g> comment 371 ** 2. address ==> address 372 ** 3. address (comment) ==> $g (comment) 373 ** 4. (comment) address ==> (comment) $g 374 ** And then there are the hard cases.... 375 ** 5. add (comment) ress ==> $g (comment) 376 ** 6. comment <address (comment)> ==> comment <$g (comment)> 377 ** 7. .... etc .... 378 ** 379 ** Parameters: 380 ** addr -- the address to be cracked. 381 ** 382 ** Returns: 383 ** a pointer to the new version. 384 ** 385 ** Side Effects: 386 ** none. 387 ** 388 ** Warning: 389 ** The return value is saved in local storage and should 390 ** be copied if it is to be reused. 391 */ 392 393 char * 394 crackaddr(addr) 395 register char *addr; 396 { 397 register char *p; 398 register int i; 399 static char buf[MAXNAME]; 400 char *rhs; 401 bool gotaddr; 402 register char *bp; 403 404 # ifdef DEBUG 405 if (tTd(33, 1)) 406 printf("crackaddr(%s)\n", addr); 407 # endif DEBUG 408 409 strcpy(buf, ""); 410 rhs = NULL; 411 412 /* strip leading spaces */ 413 while (*addr != '\0' && isspace(*addr)) 414 addr++; 415 416 /* 417 ** See if we have anything in angle brackets. If so, that is 418 ** the address part, and the rest is the comment. 419 */ 420 421 p = index(addr, '<'); 422 if (p != NULL) 423 { 424 /* copy the beginning of the addr field to the buffer */ 425 *p = '\0'; 426 strcpy(buf, addr); 427 strcat(buf, "<"); 428 *p++ = '<'; 429 430 /* skip spaces */ 431 while (isspace(*p)) 432 p++; 433 434 /* find the matching right angle bracket */ 435 addr = p; 436 for (i = 0; *p != '\0'; p++) 437 { 438 switch (*p) 439 { 440 case '<': 441 i++; 442 break; 443 444 case '>': 445 i--; 446 break; 447 } 448 if (i < 0) 449 break; 450 } 451 452 /* p now points to the closing quote (or a null byte) */ 453 if (*p != '\0') 454 { 455 /* make rhs point to the extra stuff at the end */ 456 rhs = p; 457 *p++ = '\0'; 458 } 459 } 460 461 /* 462 ** Now parse the real address part. "addr" points to the (null 463 ** terminated) version of what we are inerested in; rhs points 464 ** to the extra stuff at the end of the line, if any. 465 */ 466 467 p = addr; 468 469 /* now strip out comments */ 470 bp = &buf[strlen(buf)]; 471 gotaddr = FALSE; 472 for (; *p != '\0'; p++) 473 { 474 if (*p == '(') 475 { 476 /* copy to matching close paren */ 477 *bp++ = *p++; 478 for (i = 0; *p != '\0'; p++) 479 { 480 *bp++ = *p; 481 switch (*p) 482 { 483 case '(': 484 i++; 485 break; 486 487 case ')': 488 i--; 489 break; 490 } 491 if (i < 0) 492 break; 493 } 494 continue; 495 } 496 497 /* 498 ** If this is the first "real" character we have seen, 499 ** then we put the "$g" in the buffer now. 500 */ 501 502 if (isspace(*p)) 503 *bp++ = *p; 504 else if (!gotaddr) 505 { 506 strcpy(bp, "$g"); 507 bp += 2; 508 gotaddr = TRUE; 509 } 510 } 511 512 /* hack, hack.... strip trailing blanks */ 513 do 514 { 515 *bp-- = '\0'; 516 } while (isspace(*bp)); 517 bp++; 518 519 /* put any right hand side back on */ 520 if (rhs != NULL) 521 { 522 *rhs = '>'; 523 strcpy(bp, rhs); 524 } 525 526 # ifdef DEBUG 527 if (tTd(33, 1)) 528 printf("crackaddr=>`%s'\n", buf); 529 # endif DEBUG 530 531 return (buf); 532 } 533 /* 534 ** PUTHEADER -- put the header part of a message from the in-core copy 535 ** 536 ** Parameters: 537 ** fp -- file to put it on. 538 ** m -- mailer to use. 539 ** e -- envelope to use. 540 ** 541 ** Returns: 542 ** none. 543 ** 544 ** Side Effects: 545 ** none. 546 */ 547 548 putheader(fp, m, e) 549 register FILE *fp; 550 register MAILER *m; 551 register ENVELOPE *e; 552 { 553 char buf[BUFSIZ]; 554 register HDR *h; 555 extern char *arpadate(); 556 extern char *capitalize(); 557 char obuf[MAXLINE]; 558 bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 559 560 for (h = e->e_header; h != NULL; h = h->h_link) 561 { 562 register char *p; 563 564 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 565 !bitset(h->h_mflags, m->m_flags)) 566 continue; 567 568 p = h->h_value; 569 if (bitset(H_DEFAULT, h->h_flags)) 570 { 571 /* macro expand value if generated internally */ 572 expand(p, buf, &buf[sizeof buf], e); 573 p = buf; 574 if (p == NULL || *p == '\0') 575 continue; 576 } 577 578 if (bitset(H_FROM|H_RCPT, h->h_flags)) 579 { 580 /* address field */ 581 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 582 583 if (bitset(H_FROM, h->h_flags)) 584 oldstyle = FALSE; 585 commaize(h, p, fp, oldstyle, m); 586 } 587 else 588 { 589 /* vanilla header line */ 590 (void) sprintf(obuf, "%s: %s\n", capitalize(h->h_field), p); 591 putline(obuf, fp, fullsmtp); 592 } 593 } 594 } 595 /* 596 ** COMMAIZE -- output a header field, making a comma-translated list. 597 ** 598 ** Parameters: 599 ** h -- the header field to output. 600 ** p -- the value to put in it. 601 ** fp -- file to put it to. 602 ** oldstyle -- TRUE if this is an old style header. 603 ** m -- a pointer to the mailer descriptor. If NULL, 604 ** don't transform the name at all. 605 ** 606 ** Returns: 607 ** none. 608 ** 609 ** Side Effects: 610 ** outputs "p" to file "fp". 611 */ 612 613 commaize(h, p, fp, oldstyle, m) 614 register HDR *h; 615 register char *p; 616 FILE *fp; 617 bool oldstyle; 618 register MAILER *m; 619 { 620 register char *obp; 621 int opos; 622 bool fullsmtp = FALSE; 623 bool firstone = TRUE; 624 char obuf[MAXLINE]; 625 626 /* 627 ** Output the address list translated by the 628 ** mailer and with commas. 629 */ 630 631 # ifdef DEBUG 632 if (tTd(14, 2)) 633 printf("commaize(%s: %s)\n", h->h_field, p); 634 # endif DEBUG 635 636 if (m != NULL && bitset(M_FULLSMTP, m->m_flags)) 637 fullsmtp = TRUE; 638 639 obp = obuf; 640 (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 641 opos = strlen(h->h_field) + 2; 642 obp += opos; 643 644 /* 645 ** Run through the list of values. 646 */ 647 648 while (*p != '\0') 649 { 650 register char *name; 651 char savechar; 652 extern char *remotename(); 653 extern char *DelimChar; /* defined in prescan */ 654 655 /* 656 ** Find the end of the name. New style names 657 ** end with a comma, old style names end with 658 ** a space character. However, spaces do not 659 ** necessarily delimit an old-style name -- at 660 ** signs mean keep going. 661 */ 662 663 /* find end of name */ 664 while (isspace(*p) || *p == ',') 665 p++; 666 name = p; 667 for (;;) 668 { 669 char *oldp; 670 extern bool isatword(); 671 extern char **prescan(); 672 673 (void) prescan(p, oldstyle ? ' ' : ','); 674 p = DelimChar; 675 676 /* look to see if we have an at sign */ 677 oldp = p; 678 while (*p != '\0' && isspace(*p)) 679 p++; 680 681 if (*p != '@' && !isatword(p)) 682 { 683 p = oldp; 684 break; 685 } 686 p += *p == '@' ? 1 : 2; 687 while (*p != '\0' && isspace(*p)) 688 p++; 689 } 690 /* at the end of one complete name */ 691 692 /* strip off trailing white space */ 693 while (p >= name && (isspace(*p) || *p == ',' || *p == '\0')) 694 p--; 695 if (++p == name) 696 continue; 697 savechar = *p; 698 *p = '\0'; 699 700 /* translate the name to be relative */ 701 if (m != NULL) 702 name = remotename(name, m, bitset(H_FROM, h->h_flags)); 703 if (*name == '\0') 704 { 705 *p = savechar; 706 continue; 707 } 708 709 /* output the name with nice formatting */ 710 opos += qstrlen(name); 711 if (!firstone) 712 opos += 2; 713 if (opos > 78 && !firstone) 714 { 715 (void) sprintf(obp, ",\n"); 716 putline(obuf, fp, fullsmtp); 717 obp = obuf; 718 (void) sprintf(obp, " "); 719 obp += strlen(obp); 720 opos = 8 + strlen(name); 721 } 722 else if (!firstone) 723 { 724 (void) sprintf(obp, ", "); 725 obp += 2; 726 } 727 728 /* strip off quote bits as we output */ 729 while (*name != '\0') 730 { 731 if (bitset(0200, *name)) 732 *obp++ = '\\'; 733 *obp++ = *name++ & ~0200; 734 } 735 firstone = FALSE; 736 *p = savechar; 737 } 738 (void) strcpy(obp, "\n"); 739 putline(obuf, fp, fullsmtp); 740 } 741 /* 742 ** ISATWORD -- tell if the word we are pointing to is "at". 743 ** 744 ** Parameters: 745 ** p -- word to check. 746 ** 747 ** Returns: 748 ** TRUE -- if p is the word at. 749 ** FALSE -- otherwise. 750 ** 751 ** Side Effects: 752 ** none. 753 */ 754 755 bool 756 isatword(p) 757 register char *p; 758 { 759 extern char lower(); 760 761 if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 762 p[2] != '\0' && isspace(p[2])) 763 return (TRUE); 764 return (FALSE); 765 } 766