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