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