1 /* 2 * Copyright (c) 1983, 1995 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)headers.c 8.58 (Berkeley) 04/21/95"; 11 #endif /* not lint */ 12 13 # include <errno.h> 14 # include "sendmail.h" 15 16 /* 17 ** CHOMPHEADER -- process and save a header line. 18 ** 19 ** Called by collect and by readcf to deal with header lines. 20 ** 21 ** Parameters: 22 ** line -- header as a text line. 23 ** def -- if set, this is a default value. 24 ** hdrp -- a pointer to the place to save the header. 25 ** e -- the envelope including this header. 26 ** 27 ** Returns: 28 ** flags for this header. 29 ** 30 ** Side Effects: 31 ** The header is saved on the header list. 32 ** Contents of 'line' are destroyed. 33 */ 34 35 chompheader(line, def, hdrp, e) 36 char *line; 37 bool def; 38 HDR **hdrp; 39 register ENVELOPE *e; 40 { 41 register char *p; 42 register HDR *h; 43 HDR **hp; 44 char *fname; 45 char *fvalue; 46 struct hdrinfo *hi; 47 bool cond = FALSE; 48 bool headeronly; 49 BITMAP mopts; 50 char buf[MAXNAME + 1]; 51 52 if (tTd(31, 6)) 53 { 54 printf("chompheader: "); 55 xputs(line); 56 printf("\n"); 57 } 58 59 headeronly = hdrp != NULL; 60 if (!headeronly) 61 hdrp = &e->e_header; 62 63 /* strip off options */ 64 clrbitmap(mopts); 65 p = line; 66 if (*p == '?') 67 { 68 /* have some */ 69 register char *q = strchr(p + 1, *p); 70 71 if (q != NULL) 72 { 73 *q++ = '\0'; 74 while (*++p != '\0') 75 setbitn(*p, mopts); 76 p = q; 77 } 78 else 79 syserr("553 header syntax error, line \"%s\"", line); 80 cond = TRUE; 81 } 82 83 /* find canonical name */ 84 fname = p; 85 while (isascii(*p) && isgraph(*p) && *p != ':') 86 p++; 87 fvalue = p; 88 while (isascii(*p) && isspace(*p)) 89 p++; 90 if (*p++ != ':' || fname == fvalue) 91 { 92 syserr("553 header syntax error, line \"%s\"", line); 93 return (0); 94 } 95 *fvalue = '\0'; 96 fvalue = p; 97 98 /* strip field value on front */ 99 if (*fvalue == ' ') 100 fvalue++; 101 102 /* see if it is a known type */ 103 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 104 { 105 if (strcasecmp(hi->hi_field, fname) == 0) 106 break; 107 } 108 109 if (tTd(31, 9)) 110 { 111 if (hi->hi_field == NULL) 112 printf("no header match\n"); 113 else 114 printf("header match, hi_flags=%x\n", hi->hi_flags); 115 } 116 117 /* see if this is a resent message */ 118 if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags)) 119 e->e_flags |= EF_RESENT; 120 121 /* if this is an Errors-To: header keep track of it now */ 122 if (UseErrorsTo && !def && !headeronly && 123 bitset(H_ERRORSTO, hi->hi_flags)) 124 (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 125 126 /* if this means "end of header" quit now */ 127 if (bitset(H_EOH, hi->hi_flags)) 128 return (hi->hi_flags); 129 130 /* 131 ** Drop explicit From: if same as what we would generate. 132 ** This is to make MH (which doesn't always give a full name) 133 ** insert the full name information in all circumstances. 134 */ 135 136 p = "resent-from"; 137 if (!bitset(EF_RESENT, e->e_flags)) 138 p += 7; 139 if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) && 140 strcasecmp(fname, p) == 0) 141 { 142 if (tTd(31, 2)) 143 { 144 printf("comparing header from (%s) against default (%s or %s)\n", 145 fvalue, e->e_from.q_paddr, e->e_from.q_user); 146 } 147 if (e->e_from.q_paddr != NULL && 148 (strcmp(fvalue, e->e_from.q_paddr) == 0 || 149 strcmp(fvalue, e->e_from.q_user) == 0)) 150 return (hi->hi_flags); 151 #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ 152 #ifdef USERDB 153 else 154 { 155 auto ADDRESS a; 156 char *fancy; 157 bool oldSuprErrs = SuprErrs; 158 extern char *crackaddr(); 159 extern char *udbsender(); 160 161 /* 162 ** Try doing USERDB rewriting even on fully commented 163 ** names; this saves the "comment" information (such 164 ** as full name) and rewrites the electronic part. 165 ** 166 ** XXX This code doesn't belong here -- parsing should 167 ** XXX not be done during collect() phase because 168 ** XXX error messages can confuse the SMTP phase. 169 ** XXX Setting SuprErrs is a crude hack around this 170 ** XXX problem. 171 */ 172 173 if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 174 SuprErrs = TRUE; 175 fancy = crackaddr(fvalue); 176 if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && 177 bitnset(M_CHECKUDB, a.q_mailer->m_flags) && 178 (p = udbsender(a.q_user)) != NULL) 179 { 180 char *oldg = macvalue('g', e); 181 182 define('g', p, e); 183 expand(fancy, buf, sizeof buf, e); 184 define('g', oldg, e); 185 fvalue = buf; 186 } 187 SuprErrs = oldSuprErrs; 188 } 189 #endif 190 #endif 191 } 192 193 /* delete default value for this header */ 194 for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 195 { 196 if (strcasecmp(fname, h->h_field) == 0 && 197 bitset(H_DEFAULT, h->h_flags) && 198 !bitset(H_FORCE, h->h_flags)) 199 h->h_value = NULL; 200 } 201 202 /* create a new node */ 203 h = (HDR *) xalloc(sizeof *h); 204 h->h_field = newstr(fname); 205 h->h_value = newstr(fvalue); 206 h->h_link = NULL; 207 bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 208 *hp = h; 209 h->h_flags = hi->hi_flags; 210 if (def) 211 h->h_flags |= H_DEFAULT; 212 if (cond) 213 h->h_flags |= H_CHECK; 214 215 /* hack to see if this is a new format message */ 216 if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && 217 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 218 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 219 { 220 e->e_flags &= ~EF_OLDSTYLE; 221 } 222 223 return (h->h_flags); 224 } 225 /* 226 ** ADDHEADER -- add a header entry to the end of the queue. 227 ** 228 ** This bypasses the special checking of chompheader. 229 ** 230 ** Parameters: 231 ** field -- the name of the header field. 232 ** value -- the value of the field. 233 ** hp -- an indirect pointer to the header structure list. 234 ** 235 ** Returns: 236 ** none. 237 ** 238 ** Side Effects: 239 ** adds the field on the list of headers for this envelope. 240 */ 241 242 addheader(field, value, hdrlist) 243 char *field; 244 char *value; 245 HDR **hdrlist; 246 { 247 register HDR *h; 248 register struct hdrinfo *hi; 249 HDR **hp; 250 251 /* find info struct */ 252 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 253 { 254 if (strcasecmp(field, hi->hi_field) == 0) 255 break; 256 } 257 258 /* find current place in list -- keep back pointer? */ 259 for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 260 { 261 if (strcasecmp(field, h->h_field) == 0) 262 break; 263 } 264 265 /* allocate space for new header */ 266 h = (HDR *) xalloc(sizeof *h); 267 h->h_field = field; 268 h->h_value = newstr(value); 269 h->h_link = *hp; 270 h->h_flags = hi->hi_flags | H_DEFAULT; 271 clrbitmap(h->h_mflags); 272 *hp = h; 273 } 274 /* 275 ** HVALUE -- return value of a header. 276 ** 277 ** Only "real" fields (i.e., ones that have not been supplied 278 ** as a default) are used. 279 ** 280 ** Parameters: 281 ** field -- the field name. 282 ** header -- the header list. 283 ** 284 ** Returns: 285 ** pointer to the value part. 286 ** NULL if not found. 287 ** 288 ** Side Effects: 289 ** none. 290 */ 291 292 char * 293 hvalue(field, header) 294 char *field; 295 HDR *header; 296 { 297 register HDR *h; 298 299 for (h = header; h != NULL; h = h->h_link) 300 { 301 if (!bitset(H_DEFAULT, h->h_flags) && 302 strcasecmp(h->h_field, field) == 0) 303 return (h->h_value); 304 } 305 return (NULL); 306 } 307 /* 308 ** ISHEADER -- predicate telling if argument is a header. 309 ** 310 ** A line is a header if it has a single word followed by 311 ** optional white space followed by a colon. 312 ** 313 ** Header fields beginning with two dashes, although technically 314 ** permitted by RFC822, are automatically rejected in order 315 ** to make MIME work out. Without this we could have a technically 316 ** legal header such as ``--"foo:bar"'' that would also be a legal 317 ** MIME separator. 318 ** 319 ** Parameters: 320 ** h -- string to check for possible headerness. 321 ** 322 ** Returns: 323 ** TRUE if h is a header. 324 ** FALSE otherwise. 325 ** 326 ** Side Effects: 327 ** none. 328 */ 329 330 bool 331 isheader(h) 332 char *h; 333 { 334 register char *s = h; 335 336 if (s[0] == '-' && s[1] == '-') 337 return FALSE; 338 339 while (*s > ' ' && *s != ':' && *s != '\0') 340 s++; 341 342 if (h == s) 343 return FALSE; 344 345 /* following technically violates RFC822 */ 346 while (isascii(*s) && isspace(*s)) 347 s++; 348 349 return (*s == ':'); 350 } 351 /* 352 ** EATHEADER -- run through the stored header and extract info. 353 ** 354 ** Parameters: 355 ** e -- the envelope to process. 356 ** full -- if set, do full processing (e.g., compute 357 ** message priority). 358 ** 359 ** Returns: 360 ** none. 361 ** 362 ** Side Effects: 363 ** Sets a bunch of global variables from information 364 ** in the collected header. 365 ** Aborts the message if the hop count is exceeded. 366 */ 367 368 eatheader(e, full) 369 register ENVELOPE *e; 370 bool full; 371 { 372 register HDR *h; 373 register char *p; 374 int hopcnt = 0; 375 char *msgid; 376 char buf[MAXLINE]; 377 378 /* 379 ** Set up macros for possible expansion in headers. 380 */ 381 382 define('f', e->e_sender, e); 383 define('g', e->e_sender, e); 384 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 385 define('u', e->e_origrcpt, e); 386 else 387 define('u', NULL, e); 388 389 /* full name of from person */ 390 p = hvalue("full-name", e->e_header); 391 if (p != NULL) 392 define('x', p, e); 393 394 if (tTd(32, 1)) 395 printf("----- collected header -----\n"); 396 msgid = "<none>"; 397 for (h = e->e_header; h != NULL; h = h->h_link) 398 { 399 if (h->h_value == NULL) 400 { 401 if (tTd(32, 1)) 402 printf("%s: <NULL>\n", h->h_field); 403 continue; 404 } 405 406 /* do early binding */ 407 if (bitset(H_DEFAULT, h->h_flags)) 408 { 409 expand(h->h_value, buf, sizeof buf, e); 410 if (buf[0] != '\0') 411 { 412 h->h_value = newstr(buf); 413 h->h_flags &= ~H_DEFAULT; 414 } 415 } 416 417 if (tTd(32, 1)) 418 { 419 printf("%s: ", h->h_field); 420 xputs(h->h_value); 421 printf("\n"); 422 } 423 424 /* count the number of times it has been processed */ 425 if (bitset(H_TRACE, h->h_flags)) 426 hopcnt++; 427 428 /* send to this person if we so desire */ 429 if (GrabTo && bitset(H_RCPT, h->h_flags) && 430 !bitset(H_DEFAULT, h->h_flags) && 431 (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 432 { 433 int saveflags = e->e_flags; 434 435 (void) sendtolist(h->h_value, NULLADDR, 436 &e->e_sendqueue, 0, e); 437 438 /* delete fatal errors generated by this address */ 439 if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 440 e->e_flags &= ~EF_FATALERRS; 441 } 442 443 /* save the message-id for logging */ 444 if (full && strcasecmp(h->h_field, "message-id") == 0) 445 { 446 msgid = h->h_value; 447 while (isascii(*msgid) && isspace(*msgid)) 448 msgid++; 449 } 450 451 /* see if this is a return-receipt header */ 452 if (bitset(H_RECEIPTTO, h->h_flags)) 453 e->e_receiptto = h->h_value; 454 } 455 if (tTd(32, 1)) 456 printf("----------------------------\n"); 457 458 /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 459 if (OpMode == MD_VERIFY) 460 return; 461 462 /* store hop count */ 463 if (hopcnt > e->e_hopcount) 464 e->e_hopcount = hopcnt; 465 466 /* message priority */ 467 p = hvalue("precedence", e->e_header); 468 if (p != NULL) 469 e->e_class = priencode(p); 470 if (full) 471 { 472 e->e_msgpriority = e->e_msgsize 473 - e->e_class * WkClassFact 474 + e->e_nrcpts * WkRecipFact; 475 if (e->e_class < 0) 476 e->e_timeoutclass = TOC_NONURGENT; 477 else if (e->e_class > 0) 478 e->e_timeoutclass = TOC_URGENT; 479 } 480 481 /* message timeout priority */ 482 p = hvalue("priority", e->e_header); 483 if (full && p != NULL) 484 { 485 /* (this should be in the configuration file) */ 486 if (strcasecmp(p, "urgent")) 487 e->e_timeoutclass = TOC_URGENT; 488 else if (strcasecmp(p, "normal")) 489 e->e_timeoutclass = TOC_NORMAL; 490 else if (strcasecmp(p, "non-urgent")) 491 e->e_timeoutclass = TOC_NONURGENT; 492 } 493 494 /* date message originated */ 495 p = hvalue("posted-date", e->e_header); 496 if (p == NULL) 497 p = hvalue("date", e->e_header); 498 if (p != NULL) 499 define('a', p, e); 500 501 /* 502 ** From person in antiquated ARPANET mode 503 ** required by UK Grey Book e-mail gateways (sigh) 504 */ 505 506 if (OpMode == MD_ARPAFTP) 507 { 508 register struct hdrinfo *hi; 509 510 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 511 { 512 if (bitset(H_FROM, hi->hi_flags) && 513 (!bitset(H_RESENT, hi->hi_flags) || 514 bitset(EF_RESENT, e->e_flags)) && 515 (p = hvalue(hi->hi_field, e->e_header)) != NULL) 516 break; 517 } 518 if (hi->hi_field != NULL) 519 { 520 if (tTd(32, 2)) 521 printf("eatheader: setsender(*%s == %s)\n", 522 hi->hi_field, p); 523 setsender(p, e, NULL, TRUE); 524 } 525 } 526 527 /* 528 ** Log collection information. 529 */ 530 531 # ifdef LOG 532 if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 533 logsender(e, msgid); 534 # endif /* LOG */ 535 e->e_flags &= ~EF_LOGSENDER; 536 } 537 /* 538 ** LOGSENDER -- log sender information 539 ** 540 ** Parameters: 541 ** e -- the envelope to log 542 ** msgid -- the message id 543 ** 544 ** Returns: 545 ** none 546 */ 547 548 logsender(e, msgid) 549 register ENVELOPE *e; 550 char *msgid; 551 { 552 # ifdef LOG 553 char *name; 554 register char *sbp; 555 register char *p; 556 int l; 557 char hbuf[MAXNAME + 1]; 558 char sbuf[MAXLINE + 1]; 559 char mbuf[MAXNAME + 1]; 560 561 /* don't allow newlines in the message-id */ 562 if (msgid != NULL) 563 { 564 l = strlen(msgid); 565 if (l > sizeof mbuf - 1) 566 l = sizeof mbuf - 1; 567 bcopy(msgid, mbuf, l); 568 mbuf[l] = '\0'; 569 p = mbuf; 570 while ((p = strchr(p, '\n')) != NULL) 571 *p++ = ' '; 572 } 573 574 if (bitset(EF_RESPONSE, e->e_flags)) 575 name = "[RESPONSE]"; 576 else if ((name = macvalue('_', e)) != NULL) 577 ; 578 else if (RealHostName == NULL) 579 name = "localhost"; 580 else if (RealHostName[0] == '[') 581 name = RealHostName; 582 else 583 { 584 name = hbuf; 585 (void) sprintf(hbuf, "%.80s", RealHostName); 586 if (RealHostAddr.sa.sa_family != 0) 587 { 588 p = &hbuf[strlen(hbuf)]; 589 (void) sprintf(p, " (%s)", 590 anynet_ntoa(&RealHostAddr)); 591 } 592 } 593 594 /* some versions of syslog only take 5 printf args */ 595 # if (SYSLOG_BUFSIZE) >= 256 596 sbp = sbuf; 597 sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 598 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 599 e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 600 sbp += strlen(sbp); 601 if (msgid != NULL) 602 { 603 sprintf(sbp, ", msgid=%.100s", mbuf); 604 sbp += strlen(sbp); 605 } 606 if (e->e_bodytype != NULL) 607 { 608 (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 609 sbp += strlen(sbp); 610 } 611 p = macvalue('r', e); 612 if (p != NULL) 613 (void) sprintf(sbp, ", proto=%.20s", p); 614 syslog(LOG_INFO, "%s: %s, relay=%s", 615 e->e_id, sbuf, name); 616 617 # else /* short syslog buffer */ 618 619 syslog(LOG_INFO, "%s: from=%s", 620 e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 621 shortenstring(e->e_from.q_paddr, 83)); 622 syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 623 e->e_id, e->e_msgsize, e->e_class, 624 e->e_msgpriority, e->e_nrcpts); 625 if (msgid != NULL) 626 syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 627 sbp = sbuf; 628 sprintf(sbp, "%s:", e->e_id); 629 sbp += strlen(sbp); 630 if (e->e_bodytype != NULL) 631 { 632 sprintf(sbp, " bodytype=%s,", e->e_bodytype); 633 sbp += strlen(sbp); 634 } 635 p = macvalue('r', e); 636 if (p != NULL) 637 { 638 sprintf(sbp, " proto=%s,", p); 639 sbp += strlen(sbp); 640 } 641 syslog(LOG_INFO, "%s relay=%s", sbuf, name); 642 # endif 643 # endif 644 } 645 /* 646 ** PRIENCODE -- encode external priority names into internal values. 647 ** 648 ** Parameters: 649 ** p -- priority in ascii. 650 ** 651 ** Returns: 652 ** priority as a numeric level. 653 ** 654 ** Side Effects: 655 ** none. 656 */ 657 658 priencode(p) 659 char *p; 660 { 661 register int i; 662 663 for (i = 0; i < NumPriorities; i++) 664 { 665 if (!strcasecmp(p, Priorities[i].pri_name)) 666 return (Priorities[i].pri_val); 667 } 668 669 /* unknown priority */ 670 return (0); 671 } 672 /* 673 ** CRACKADDR -- parse an address and turn it into a macro 674 ** 675 ** This doesn't actually parse the address -- it just extracts 676 ** it and replaces it with "$g". The parse is totally ad hoc 677 ** and isn't even guaranteed to leave something syntactically 678 ** identical to what it started with. However, it does leave 679 ** something semantically identical. 680 ** 681 ** This algorithm has been cleaned up to handle a wider range 682 ** of cases -- notably quoted and backslash escaped strings. 683 ** This modification makes it substantially better at preserving 684 ** the original syntax. 685 ** 686 ** Parameters: 687 ** addr -- the address to be cracked. 688 ** 689 ** Returns: 690 ** a pointer to the new version. 691 ** 692 ** Side Effects: 693 ** none. 694 ** 695 ** Warning: 696 ** The return value is saved in local storage and should 697 ** be copied if it is to be reused. 698 */ 699 700 char * 701 crackaddr(addr) 702 register char *addr; 703 { 704 register char *p; 705 register char c; 706 int cmtlev; 707 int realcmtlev; 708 int anglelev, realanglelev; 709 int copylev; 710 bool qmode; 711 bool realqmode; 712 bool skipping; 713 bool putgmac = FALSE; 714 bool quoteit = FALSE; 715 bool gotangle = FALSE; 716 bool gotcolon = FALSE; 717 register char *bp; 718 char *buflim; 719 char *bufhead; 720 char *addrhead; 721 static char buf[MAXNAME + 1]; 722 723 if (tTd(33, 1)) 724 printf("crackaddr(%s)\n", addr); 725 726 /* strip leading spaces */ 727 while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 728 addr++; 729 730 /* 731 ** Start by assuming we have no angle brackets. This will be 732 ** adjusted later if we find them. 733 */ 734 735 bp = bufhead = buf; 736 buflim = &buf[sizeof buf - 5]; 737 p = addrhead = addr; 738 copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 739 qmode = realqmode = FALSE; 740 741 while ((c = *p++) != '\0') 742 { 743 /* 744 ** If the buffer is overful, go into a special "skipping" 745 ** mode that tries to keep legal syntax but doesn't actually 746 ** output things. 747 */ 748 749 skipping = bp >= buflim; 750 751 if (copylev > 0 && !skipping) 752 *bp++ = c; 753 754 /* check for backslash escapes */ 755 if (c == '\\') 756 { 757 /* arrange to quote the address */ 758 if (cmtlev <= 0 && !qmode) 759 quoteit = TRUE; 760 761 if ((c = *p++) == '\0') 762 { 763 /* too far */ 764 p--; 765 goto putg; 766 } 767 if (copylev > 0 && !skipping) 768 *bp++ = c; 769 goto putg; 770 } 771 772 /* check for quoted strings */ 773 if (c == '"' && cmtlev <= 0) 774 { 775 qmode = !qmode; 776 if (copylev > 0 && !skipping) 777 realqmode = !realqmode; 778 continue; 779 } 780 if (qmode) 781 goto putg; 782 783 /* check for comments */ 784 if (c == '(') 785 { 786 cmtlev++; 787 788 /* allow space for closing paren */ 789 if (!skipping) 790 { 791 buflim--; 792 realcmtlev++; 793 if (copylev++ <= 0) 794 { 795 *bp++ = ' '; 796 *bp++ = c; 797 } 798 } 799 } 800 if (cmtlev > 0) 801 { 802 if (c == ')') 803 { 804 cmtlev--; 805 copylev--; 806 if (!skipping) 807 { 808 realcmtlev--; 809 buflim++; 810 } 811 } 812 continue; 813 } 814 else if (c == ')') 815 { 816 /* syntax error: unmatched ) */ 817 if (copylev > 0 && !skipping) 818 bp--; 819 } 820 821 /* check for group: list; syntax */ 822 if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) 823 { 824 register char *q; 825 826 if (*p == ':') 827 { 828 /* special case -- :: syntax */ 829 if (cmtlev <= 0 && !qmode) 830 quoteit = TRUE; 831 if (copylev > 0 && !skipping) 832 { 833 *bp++ = c; 834 *bp++ = c; 835 } 836 p++; 837 goto putg; 838 } 839 840 gotcolon = TRUE; 841 842 bp = bufhead; 843 if (quoteit) 844 { 845 *bp++ = '"'; 846 847 /* back up over the ':' and any spaces */ 848 --p; 849 while (isascii(*--p) && isspace(*p)) 850 continue; 851 p++; 852 } 853 for (q = addrhead; q < p; ) 854 { 855 c = *q++; 856 if (bp < buflim) 857 { 858 if (quoteit && c == '"') 859 *bp++ = '\\'; 860 *bp++ = c; 861 } 862 } 863 if (quoteit) 864 { 865 if (bp == &bufhead[1]) 866 bp--; 867 else 868 *bp++ = '"'; 869 while ((c = *p++) != ':') 870 { 871 if (bp < buflim) 872 *bp++ = c; 873 } 874 *bp++ = c; 875 } 876 877 /* any trailing white space is part of group: */ 878 while (isascii(*p) && isspace(*p) && bp < buflim) 879 *bp++ = *p++; 880 copylev = 0; 881 putgmac = quoteit = FALSE; 882 bufhead = bp; 883 addrhead = p; 884 continue; 885 } 886 887 if (c == ';' && copylev <= 0 && !ColonOkInAddr) 888 { 889 register char *q = p; 890 891 if (bp < buflim) 892 *bp++ = c; 893 } 894 895 /* check for characters that may have to be quoted */ 896 if (strchr(".'@,;:\\()[]", c) != NULL) 897 { 898 /* 899 ** If these occur as the phrase part of a <> 900 ** construct, but are not inside of () or already 901 ** quoted, they will have to be quoted. Note that 902 ** now (but don't actually do the quoting). 903 */ 904 905 if (cmtlev <= 0 && !qmode) 906 quoteit = TRUE; 907 } 908 909 /* check for angle brackets */ 910 if (c == '<') 911 { 912 register char *q; 913 914 /* assume first of two angles is bogus */ 915 if (gotangle) 916 quoteit = TRUE; 917 gotangle = TRUE; 918 919 /* oops -- have to change our mind */ 920 anglelev = 1; 921 if (!skipping) 922 realanglelev = 1; 923 924 bp = bufhead; 925 if (quoteit) 926 { 927 *bp++ = '"'; 928 929 /* back up over the '<' and any spaces */ 930 --p; 931 while (isascii(*--p) && isspace(*p)) 932 continue; 933 p++; 934 } 935 for (q = addrhead; q < p; ) 936 { 937 c = *q++; 938 if (bp < buflim) 939 { 940 if (quoteit && c == '"') 941 *bp++ = '\\'; 942 *bp++ = c; 943 } 944 } 945 if (quoteit) 946 { 947 if (bp == &buf[1]) 948 bp--; 949 else 950 *bp++ = '"'; 951 while ((c = *p++) != '<') 952 { 953 if (bp < buflim) 954 *bp++ = c; 955 } 956 *bp++ = c; 957 } 958 copylev = 0; 959 putgmac = quoteit = FALSE; 960 continue; 961 } 962 963 if (c == '>') 964 { 965 if (anglelev > 0) 966 { 967 anglelev--; 968 if (!skipping) 969 { 970 realanglelev--; 971 buflim++; 972 } 973 } 974 else if (!skipping) 975 { 976 /* syntax error: unmatched > */ 977 if (copylev > 0) 978 bp--; 979 quoteit = TRUE; 980 continue; 981 } 982 if (copylev++ <= 0) 983 *bp++ = c; 984 continue; 985 } 986 987 /* must be a real address character */ 988 putg: 989 if (copylev <= 0 && !putgmac) 990 { 991 *bp++ = MACROEXPAND; 992 *bp++ = 'g'; 993 putgmac = TRUE; 994 } 995 } 996 997 /* repair any syntactic damage */ 998 if (realqmode) 999 *bp++ = '"'; 1000 while (realcmtlev-- > 0) 1001 *bp++ = ')'; 1002 while (realanglelev-- > 0) 1003 *bp++ = '>'; 1004 *bp++ = '\0'; 1005 1006 if (tTd(33, 1)) 1007 printf("crackaddr=>`%s'\n", buf); 1008 1009 return (buf); 1010 } 1011 /* 1012 ** PUTHEADER -- put the header part of a message from the in-core copy 1013 ** 1014 ** Parameters: 1015 ** mci -- the connection information. 1016 ** h -- the header to put. 1017 ** e -- envelope to use. 1018 ** 1019 ** Returns: 1020 ** none. 1021 ** 1022 ** Side Effects: 1023 ** none. 1024 */ 1025 1026 /* 1027 * Macro for fast max (not available in e.g. DG/UX, 386/ix). 1028 */ 1029 #ifndef MAX 1030 # define MAX(a,b) (((a)>(b))?(a):(b)) 1031 #endif 1032 1033 putheader(mci, h, e) 1034 register MCI *mci; 1035 register HDR *h; 1036 register ENVELOPE *e; 1037 { 1038 char buf[MAX(MAXLINE,BUFSIZ)]; 1039 char obuf[MAXLINE]; 1040 1041 if (tTd(34, 1)) 1042 printf("--- putheader, mailer = %s ---\n", 1043 mci->mci_mailer->m_name); 1044 1045 mci->mci_flags |= MCIF_INHEADER; 1046 for (; h != NULL; h = h->h_link) 1047 { 1048 register char *p; 1049 extern bool bitintersect(); 1050 1051 if (tTd(34, 11)) 1052 { 1053 printf(" %s: ", h->h_field); 1054 xputs(h->h_value); 1055 } 1056 1057 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 1058 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 1059 { 1060 if (tTd(34, 11)) 1061 printf(" (skipped)\n"); 1062 continue; 1063 } 1064 1065 /* handle Resent-... headers specially */ 1066 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1067 { 1068 if (tTd(34, 11)) 1069 printf(" (skipped (resent))\n"); 1070 continue; 1071 } 1072 1073 /* suppress return receipts if requested */ 1074 if (bitset(H_RECEIPTTO, h->h_flags) && 1075 bitset(EF_NORECEIPT, e->e_flags)) 1076 { 1077 if (tTd(34, 11)) 1078 printf(" (skipped (receipt))\n"); 1079 continue; 1080 } 1081 1082 /* suppress Content-Transfer-Encoding: if we are MIMEing */ 1083 if (bitset(H_CTE, h->h_flags) && 1084 bitset(MCIF_CVT8TO7, mci->mci_flags)) 1085 { 1086 if (tTd(34, 11)) 1087 printf(" (skipped (content-transfer-encoding))\n"); 1088 continue; 1089 } 1090 1091 /* macro expand value if generated internally */ 1092 p = h->h_value; 1093 if (bitset(H_DEFAULT, h->h_flags)) 1094 { 1095 expand(p, buf, sizeof buf, e); 1096 p = buf; 1097 if (p == NULL || *p == '\0') 1098 { 1099 if (tTd(34, 11)) 1100 printf(" (skipped -- null value)\n"); 1101 continue; 1102 } 1103 } 1104 1105 if (tTd(34, 11)) 1106 printf("\n"); 1107 1108 if (bitset(H_STRIPVAL, h->h_flags)) 1109 { 1110 /* empty field */ 1111 (void) sprintf(obuf, "%s:", h->h_field); 1112 putline(obuf, mci); 1113 } 1114 else if (bitset(H_FROM|H_RCPT, h->h_flags)) 1115 { 1116 /* address field */ 1117 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1118 1119 if (bitset(H_FROM, h->h_flags)) 1120 oldstyle = FALSE; 1121 commaize(h, p, oldstyle, mci, e); 1122 } 1123 else 1124 { 1125 /* vanilla header line */ 1126 register char *nlp; 1127 1128 (void) sprintf(obuf, "%s: ", h->h_field); 1129 while ((nlp = strchr(p, '\n')) != NULL) 1130 { 1131 *nlp = '\0'; 1132 (void) strcat(obuf, p); 1133 *nlp = '\n'; 1134 putline(obuf, mci); 1135 p = ++nlp; 1136 obuf[0] = '\0'; 1137 } 1138 (void) strcat(obuf, p); 1139 putline(obuf, mci); 1140 } 1141 } 1142 1143 /* 1144 ** If we are converting this to a MIME message, add the 1145 ** MIME headers. 1146 */ 1147 1148 if (bitset(MM_MIME8BIT, MimeMode) && 1149 bitset(EF_HAS8BIT, e->e_flags) && 1150 !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 1151 !bitset(MCIF_CVT8TO7, mci->mci_flags)) 1152 { 1153 if (hvalue("MIME-Version", e->e_header) == NULL) 1154 putline("MIME-Version: 1.0", mci); 1155 if (hvalue("Content-Type", e->e_header) == NULL) 1156 { 1157 sprintf(obuf, "Content-Type: text/plain; charset=%s", 1158 defcharset(e)); 1159 putline(obuf, mci); 1160 } 1161 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 1162 putline("Content-Transfer-Encoding: 8bit", mci); 1163 } 1164 } 1165 /* 1166 ** COMMAIZE -- output a header field, making a comma-translated list. 1167 ** 1168 ** Parameters: 1169 ** h -- the header field to output. 1170 ** p -- the value to put in it. 1171 ** oldstyle -- TRUE if this is an old style header. 1172 ** mci -- the connection information. 1173 ** e -- the envelope containing the message. 1174 ** 1175 ** Returns: 1176 ** none. 1177 ** 1178 ** Side Effects: 1179 ** outputs "p" to file "fp". 1180 */ 1181 1182 void 1183 commaize(h, p, oldstyle, mci, e) 1184 register HDR *h; 1185 register char *p; 1186 bool oldstyle; 1187 register MCI *mci; 1188 register ENVELOPE *e; 1189 { 1190 register char *obp; 1191 int opos; 1192 int omax; 1193 bool firstone = TRUE; 1194 char obuf[MAXLINE + 3]; 1195 1196 /* 1197 ** Output the address list translated by the 1198 ** mailer and with commas. 1199 */ 1200 1201 if (tTd(14, 2)) 1202 printf("commaize(%s: %s)\n", h->h_field, p); 1203 1204 obp = obuf; 1205 (void) sprintf(obp, "%s: ", h->h_field); 1206 opos = strlen(h->h_field) + 2; 1207 obp += opos; 1208 omax = mci->mci_mailer->m_linelimit - 2; 1209 if (omax < 0 || omax > 78) 1210 omax = 78; 1211 1212 /* 1213 ** Run through the list of values. 1214 */ 1215 1216 while (*p != '\0') 1217 { 1218 register char *name; 1219 register int c; 1220 char savechar; 1221 int flags; 1222 auto int stat; 1223 1224 /* 1225 ** Find the end of the name. New style names 1226 ** end with a comma, old style names end with 1227 ** a space character. However, spaces do not 1228 ** necessarily delimit an old-style name -- at 1229 ** signs mean keep going. 1230 */ 1231 1232 /* find end of name */ 1233 while ((isascii(*p) && isspace(*p)) || *p == ',') 1234 p++; 1235 name = p; 1236 for (;;) 1237 { 1238 auto char *oldp; 1239 char pvpbuf[PSBUFSIZE]; 1240 1241 (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 1242 sizeof pvpbuf, &oldp, NULL); 1243 p = oldp; 1244 1245 /* look to see if we have an at sign */ 1246 while (*p != '\0' && isascii(*p) && isspace(*p)) 1247 p++; 1248 1249 if (*p != '@') 1250 { 1251 p = oldp; 1252 break; 1253 } 1254 p += *p == '@' ? 1 : 2; 1255 while (*p != '\0' && isascii(*p) && isspace(*p)) 1256 p++; 1257 } 1258 /* at the end of one complete name */ 1259 1260 /* strip off trailing white space */ 1261 while (p >= name && 1262 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1263 p--; 1264 if (++p == name) 1265 continue; 1266 savechar = *p; 1267 *p = '\0'; 1268 1269 /* translate the name to be relative */ 1270 flags = RF_HEADERADDR|RF_ADDDOMAIN; 1271 if (bitset(H_FROM, h->h_flags)) 1272 flags |= RF_SENDERADDR; 1273 #ifdef USERDB 1274 else if (e->e_from.q_mailer != NULL && 1275 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 1276 { 1277 extern char *udbsender(); 1278 1279 name = udbsender(name); 1280 } 1281 #endif 1282 stat = EX_OK; 1283 name = remotename(name, mci->mci_mailer, flags, &stat, e); 1284 if (*name == '\0') 1285 { 1286 *p = savechar; 1287 continue; 1288 } 1289 1290 /* output the name with nice formatting */ 1291 opos += strlen(name); 1292 if (!firstone) 1293 opos += 2; 1294 if (opos > omax && !firstone) 1295 { 1296 (void) strcpy(obp, ",\n"); 1297 putline(obuf, mci); 1298 obp = obuf; 1299 (void) strcpy(obp, " "); 1300 opos = strlen(obp); 1301 obp += opos; 1302 opos += strlen(name); 1303 } 1304 else if (!firstone) 1305 { 1306 (void) strcpy(obp, ", "); 1307 obp += 2; 1308 } 1309 1310 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 1311 *obp++ = c; 1312 firstone = FALSE; 1313 *p = savechar; 1314 } 1315 (void) strcpy(obp, "\n"); 1316 putline(obuf, mci); 1317 } 1318 /* 1319 ** COPYHEADER -- copy header list 1320 ** 1321 ** This routine is the equivalent of newstr for header lists 1322 ** 1323 ** Parameters: 1324 ** header -- list of header structures to copy. 1325 ** 1326 ** Returns: 1327 ** a copy of 'header'. 1328 ** 1329 ** Side Effects: 1330 ** none. 1331 */ 1332 1333 HDR * 1334 copyheader(header) 1335 register HDR *header; 1336 { 1337 register HDR *newhdr; 1338 HDR *ret; 1339 register HDR **tail = &ret; 1340 1341 while (header != NULL) 1342 { 1343 newhdr = (HDR *) xalloc(sizeof(HDR)); 1344 STRUCTCOPY(*header, *newhdr); 1345 *tail = newhdr; 1346 tail = &newhdr->h_link; 1347 header = header->h_link; 1348 } 1349 *tail = NULL; 1350 1351 return ret; 1352 } 1353