1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)headers.c 6.26 (Berkeley) 03/24/93"; 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 ** e -- the envelope including this header. 25 ** 26 ** Returns: 27 ** flags for this header. 28 ** 29 ** Side Effects: 30 ** The header is saved on the header list. 31 ** Contents of 'line' are destroyed. 32 */ 33 34 chompheader(line, def, e) 35 char *line; 36 bool def; 37 register ENVELOPE *e; 38 { 39 register char *p; 40 register HDR *h; 41 HDR **hp; 42 char *fname; 43 char *fvalue; 44 struct hdrinfo *hi; 45 bool cond = FALSE; 46 BITMAP mopts; 47 48 if (tTd(31, 6)) 49 printf("chompheader: %s\n", line); 50 51 /* strip off options */ 52 clrbitmap(mopts); 53 p = line; 54 if (*p == '?') 55 { 56 /* have some */ 57 register char *q = strchr(p + 1, *p); 58 59 if (q != NULL) 60 { 61 *q++ = '\0'; 62 while (*++p != '\0') 63 setbitn(*p, mopts); 64 p = q; 65 } 66 else 67 usrerr("553 header syntax error, line \"%s\"", line); 68 cond = TRUE; 69 } 70 71 /* find canonical name */ 72 fname = p; 73 p = strchr(p, ':'); 74 if (p == NULL) 75 { 76 syserr("553 header syntax error, line \"%s\"", line); 77 return (0); 78 } 79 fvalue = &p[1]; 80 while (isascii(*--p) && isspace(*p)) 81 continue; 82 *++p = '\0'; 83 makelower(fname); 84 85 /* strip field value on front */ 86 if (*fvalue == ' ') 87 fvalue++; 88 89 /* see if it is a known type */ 90 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 91 { 92 if (strcmp(hi->hi_field, fname) == 0) 93 break; 94 } 95 96 /* see if this is a resent message */ 97 if (!def && bitset(H_RESENT, hi->hi_flags)) 98 e->e_flags |= EF_RESENT; 99 100 /* if this means "end of header" quit now */ 101 if (bitset(H_EOH, hi->hi_flags)) 102 return (hi->hi_flags); 103 104 /* drop explicit From: if same as what we would generate -- for MH */ 105 p = "resent-from"; 106 if (!bitset(EF_RESENT, e->e_flags)) 107 p += 7; 108 if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcmp(fname, p) == 0) 109 { 110 if (e->e_from.q_paddr != NULL && 111 strcmp(fvalue, e->e_from.q_paddr) == 0) 112 return (hi->hi_flags); 113 } 114 115 /* delete default value for this header */ 116 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 117 { 118 if (strcmp(fname, h->h_field) == 0 && 119 bitset(H_DEFAULT, h->h_flags) && 120 !bitset(H_FORCE, h->h_flags)) 121 h->h_value = NULL; 122 } 123 124 /* create a new node */ 125 h = (HDR *) xalloc(sizeof *h); 126 h->h_field = newstr(fname); 127 h->h_value = NULL; 128 h->h_link = NULL; 129 bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 130 *hp = h; 131 h->h_flags = hi->hi_flags; 132 if (def) 133 h->h_flags |= H_DEFAULT; 134 if (cond) 135 h->h_flags |= H_CHECK; 136 if (h->h_value != NULL) 137 free((char *) h->h_value); 138 h->h_value = newstr(fvalue); 139 140 /* hack to see if this is a new format message */ 141 if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 142 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 143 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 144 { 145 e->e_flags &= ~EF_OLDSTYLE; 146 } 147 148 return (h->h_flags); 149 } 150 /* 151 ** ADDHEADER -- add a header entry to the end of the queue. 152 ** 153 ** This bypasses the special checking of chompheader. 154 ** 155 ** Parameters: 156 ** field -- the name of the header field. It must be 157 ** lower-cased. 158 ** value -- the value of the field. 159 ** e -- the envelope to add them to. 160 ** 161 ** Returns: 162 ** none. 163 ** 164 ** Side Effects: 165 ** adds the field on the list of headers for this envelope. 166 */ 167 168 addheader(field, value, e) 169 char *field; 170 char *value; 171 ENVELOPE *e; 172 { 173 register HDR *h; 174 register struct hdrinfo *hi; 175 HDR **hp; 176 177 /* find info struct */ 178 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 179 { 180 if (strcmp(field, hi->hi_field) == 0) 181 break; 182 } 183 184 /* find current place in list -- keep back pointer? */ 185 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 186 { 187 if (strcmp(field, h->h_field) == 0) 188 break; 189 } 190 191 /* allocate space for new header */ 192 h = (HDR *) xalloc(sizeof *h); 193 h->h_field = field; 194 h->h_value = newstr(value); 195 h->h_link = *hp; 196 h->h_flags = hi->hi_flags | H_DEFAULT; 197 clrbitmap(h->h_mflags); 198 *hp = h; 199 } 200 /* 201 ** HVALUE -- return value of a header. 202 ** 203 ** Only "real" fields (i.e., ones that have not been supplied 204 ** as a default) are used. 205 ** 206 ** Parameters: 207 ** field -- the field name. 208 ** e -- the envelope containing the header. 209 ** 210 ** Returns: 211 ** pointer to the value part. 212 ** NULL if not found. 213 ** 214 ** Side Effects: 215 ** none. 216 */ 217 218 char * 219 hvalue(field, e) 220 char *field; 221 register ENVELOPE *e; 222 { 223 register HDR *h; 224 225 for (h = e->e_header; h != NULL; h = h->h_link) 226 { 227 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 228 return (h->h_value); 229 } 230 return (NULL); 231 } 232 /* 233 ** ISHEADER -- predicate telling if argument is a header. 234 ** 235 ** A line is a header if it has a single word followed by 236 ** optional white space followed by a colon. 237 ** 238 ** Parameters: 239 ** s -- string to check for possible headerness. 240 ** 241 ** Returns: 242 ** TRUE if s is a header. 243 ** FALSE otherwise. 244 ** 245 ** Side Effects: 246 ** none. 247 */ 248 249 bool 250 isheader(s) 251 register char *s; 252 { 253 while (*s > ' ' && *s != ':' && *s != '\0') 254 s++; 255 256 /* following technically violates RFC822 */ 257 while (isascii(*s) && isspace(*s)) 258 s++; 259 260 return (*s == ':'); 261 } 262 /* 263 ** EATHEADER -- run through the stored header and extract info. 264 ** 265 ** Parameters: 266 ** e -- the envelope to process. 267 ** 268 ** Returns: 269 ** none. 270 ** 271 ** Side Effects: 272 ** Sets a bunch of global variables from information 273 ** in the collected header. 274 ** Aborts the message if the hop count is exceeded. 275 */ 276 277 eatheader(e) 278 register ENVELOPE *e; 279 { 280 register HDR *h; 281 register char *p; 282 int hopcnt = 0; 283 char *msgid; 284 char buf[MAXLINE]; 285 286 /* 287 ** Set up macros for possible expansion in headers. 288 */ 289 290 define('f', e->e_sender, e); 291 define('g', e->e_sender, e); 292 293 if (tTd(32, 1)) 294 printf("----- collected header -----\n"); 295 msgid = "<none>"; 296 for (h = e->e_header; h != NULL; h = h->h_link) 297 { 298 extern char *capitalize(); 299 300 /* do early binding */ 301 if (bitset(H_DEFAULT, h->h_flags) && h->h_value != NULL) 302 { 303 expand(h->h_value, buf, &buf[sizeof buf], e); 304 if (buf[0] != '\0') 305 { 306 h->h_value = newstr(buf); 307 h->h_flags &= ~H_DEFAULT; 308 } 309 } 310 311 if (tTd(32, 1)) 312 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 313 314 /* count the number of times it has been processed */ 315 if (bitset(H_TRACE, h->h_flags)) 316 hopcnt++; 317 318 /* send to this person if we so desire */ 319 if (GrabTo && bitset(H_RCPT, h->h_flags) && 320 !bitset(H_DEFAULT, h->h_flags) && 321 (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 322 { 323 (void) sendtolist(h->h_value, (ADDRESS *) NULL, 324 &e->e_sendqueue, e); 325 } 326 327 /* save the message-id for logging */ 328 if (!bitset(EF_QUEUERUN, e->e_flags) && h->h_value != NULL && 329 strcmp(h->h_field, "message-id") == 0) 330 { 331 msgid = h->h_value; 332 } 333 334 /* see if this is a return-receipt header */ 335 if (bitset(H_RECEIPTTO, h->h_flags)) 336 e->e_receiptto = h->h_value; 337 338 /* see if this is an errors-to header */ 339 if (bitset(H_ERRORSTO, h->h_flags)) 340 (void) sendtolist(h->h_value, (ADDRESS *) NULL, 341 &e->e_errorqueue, e); 342 } 343 if (tTd(32, 1)) 344 printf("----------------------------\n"); 345 346 /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 347 if (OpMode == MD_VERIFY) 348 return; 349 350 /* store hop count */ 351 if (hopcnt > e->e_hopcount) 352 e->e_hopcount = hopcnt; 353 354 /* message priority */ 355 p = hvalue("precedence", e); 356 if (p != NULL) 357 e->e_class = priencode(p); 358 if (!bitset(EF_QUEUERUN, e->e_flags)) 359 e->e_msgpriority = e->e_msgsize 360 - e->e_class * WkClassFact 361 + e->e_nrcpts * WkRecipFact; 362 363 /* full name of from person */ 364 p = hvalue("full-name", e); 365 if (p != NULL) 366 define('x', p, e); 367 368 /* date message originated */ 369 p = hvalue("posted-date", e); 370 if (p == NULL) 371 p = hvalue("date", e); 372 if (p != NULL) 373 define('a', p, e); 374 375 /* 376 ** Log collection information. 377 */ 378 379 # ifdef LOG 380 if (!bitset(EF_QUEUERUN, e->e_flags) && LogLevel > 4) 381 { 382 char *name; 383 char hbuf[MAXNAME]; 384 char sbuf[MAXLINE]; 385 386 if (bitset(EF_RESPONSE, e->e_flags)) 387 name = "[RESPONSE]"; 388 else if (RealHostName[0] == '[') 389 name = RealHostName; 390 else 391 { 392 extern char *anynet_ntoa(); 393 394 name = hbuf; 395 (void) sprintf(hbuf, "%.80s", RealHostName); 396 if (RealHostAddr.sa.sa_family != 0) 397 { 398 p = &hbuf[strlen(hbuf)]; 399 (void) sprintf(p, " (%s)", 400 anynet_ntoa(&RealHostAddr)); 401 } 402 } 403 404 /* some versions of syslog only take 5 printf args */ 405 sprintf(sbuf, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s", 406 e->e_from.q_paddr, e->e_msgsize, e->e_class, 407 e->e_msgpriority, e->e_nrcpts, msgid); 408 syslog(LOG_INFO, "%s: %s, relay=%s", 409 e->e_id, sbuf, name); 410 } 411 # endif /* LOG */ 412 } 413 /* 414 ** PRIENCODE -- encode external priority names into internal values. 415 ** 416 ** Parameters: 417 ** p -- priority in ascii. 418 ** 419 ** Returns: 420 ** priority as a numeric level. 421 ** 422 ** Side Effects: 423 ** none. 424 */ 425 426 priencode(p) 427 char *p; 428 { 429 register int i; 430 431 for (i = 0; i < NumPriorities; i++) 432 { 433 if (!strcasecmp(p, Priorities[i].pri_name)) 434 return (Priorities[i].pri_val); 435 } 436 437 /* unknown priority */ 438 return (0); 439 } 440 /* 441 ** CRACKADDR -- parse an address and turn it into a macro 442 ** 443 ** This doesn't actually parse the address -- it just extracts 444 ** it and replaces it with "$g". The parse is totally ad hoc 445 ** and isn't even guaranteed to leave something syntactically 446 ** identical to what it started with. However, it does leave 447 ** something semantically identical. 448 ** 449 ** This algorithm has been cleaned up to handle a wider range 450 ** of cases -- notably quoted and backslash escaped strings. 451 ** This modification makes it substantially better at preserving 452 ** the original syntax. 453 ** 454 ** Parameters: 455 ** addr -- the address to be cracked. 456 ** 457 ** Returns: 458 ** a pointer to the new version. 459 ** 460 ** Side Effects: 461 ** none. 462 ** 463 ** Warning: 464 ** The return value is saved in local storage and should 465 ** be copied if it is to be reused. 466 */ 467 468 char * 469 crackaddr(addr) 470 register char *addr; 471 { 472 register char *p; 473 register char c; 474 int cmtlev; 475 int realcmtlev; 476 int anglelev, realanglelev; 477 int copylev; 478 bool qmode; 479 bool realqmode; 480 bool skipping; 481 bool putgmac = FALSE; 482 bool quoteit = FALSE; 483 register char *bp; 484 char *buflim; 485 static char buf[MAXNAME]; 486 487 if (tTd(33, 1)) 488 printf("crackaddr(%s)\n", addr); 489 490 /* strip leading spaces */ 491 while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 492 addr++; 493 494 /* 495 ** Start by assuming we have no angle brackets. This will be 496 ** adjusted later if we find them. 497 */ 498 499 bp = buf; 500 buflim = &buf[sizeof buf - 5]; 501 p = addr; 502 copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 503 qmode = realqmode = FALSE; 504 505 while ((c = *p++) != '\0') 506 { 507 /* 508 ** If the buffer is overful, go into a special "skipping" 509 ** mode that tries to keep legal syntax but doesn't actually 510 ** output things. 511 */ 512 513 skipping = bp >= buflim; 514 515 if (copylev > 0 && !skipping) 516 *bp++ = c; 517 518 /* check for backslash escapes */ 519 if (c == '\\') 520 { 521 if ((c = *p++) == '\0') 522 { 523 /* too far */ 524 p--; 525 goto putg; 526 } 527 if (copylev > 0 && !skipping) 528 *bp++ = c; 529 goto putg; 530 } 531 532 /* check for quoted strings */ 533 if (c == '"') 534 { 535 qmode = !qmode; 536 if (copylev > 0 && !skipping) 537 realqmode = !realqmode; 538 continue; 539 } 540 if (qmode) 541 goto putg; 542 543 /* check for comments */ 544 if (c == '(') 545 { 546 cmtlev++; 547 548 /* allow space for closing paren */ 549 if (!skipping) 550 { 551 buflim--; 552 realcmtlev++; 553 if (copylev++ <= 0) 554 { 555 *bp++ = ' '; 556 *bp++ = c; 557 } 558 } 559 } 560 if (cmtlev > 0) 561 { 562 if (c == ')') 563 { 564 cmtlev--; 565 copylev--; 566 if (!skipping) 567 { 568 realcmtlev--; 569 buflim++; 570 } 571 } 572 continue; 573 } 574 else if (c == ')') 575 { 576 /* syntax error: unmatched ) */ 577 if (!skipping) 578 bp--; 579 } 580 581 582 /* check for characters that may have to be quoted */ 583 if (strchr(".'@,;:\\()", c) != NULL) 584 { 585 /* 586 ** If these occur as the phrase part of a <> 587 ** construct, but are not inside of () or already 588 ** quoted, they will have to be quoted. Note that 589 ** now (but don't actually do the quoting). 590 */ 591 592 if (cmtlev <= 0 && !qmode) 593 quoteit = TRUE; 594 } 595 596 /* check for angle brackets */ 597 if (c == '<') 598 { 599 register char *q; 600 601 /* oops -- have to change our mind */ 602 anglelev++; 603 if (!skipping) 604 realanglelev++; 605 606 bp = buf; 607 if (quoteit) 608 { 609 *bp++ = '"'; 610 611 /* back up over the '<' and any spaces */ 612 --p; 613 while (isascii(*--p) && isspace(*p)) 614 continue; 615 p++; 616 } 617 for (q = addr; q < p; ) 618 { 619 c = *q++; 620 if (bp < buflim) 621 { 622 if (quoteit && c == '"') 623 *bp++ = '\\'; 624 *bp++ = c; 625 } 626 } 627 if (quoteit) 628 { 629 *bp++ = '"'; 630 while ((c = *p++) != '<') 631 { 632 if (bp < buflim) 633 *bp++ = c; 634 } 635 *bp++ = c; 636 } 637 copylev = 0; 638 putgmac = quoteit = FALSE; 639 continue; 640 } 641 642 if (c == '>') 643 { 644 if (anglelev > 0) 645 { 646 anglelev--; 647 if (!skipping) 648 { 649 realanglelev--; 650 buflim++; 651 } 652 } 653 else if (!skipping) 654 { 655 /* syntax error: unmatched > */ 656 if (copylev > 0) 657 bp--; 658 continue; 659 } 660 if (copylev++ <= 0) 661 *bp++ = c; 662 continue; 663 } 664 665 /* must be a real address character */ 666 putg: 667 if (copylev <= 0 && !putgmac) 668 { 669 *bp++ = MACROEXPAND; 670 *bp++ = 'g'; 671 putgmac = TRUE; 672 } 673 } 674 675 /* repair any syntactic damage */ 676 if (realqmode) 677 *bp++ = '"'; 678 while (realcmtlev-- > 0) 679 *bp++ = ')'; 680 while (realanglelev-- > 0) 681 *bp++ = '>'; 682 *bp++ = '\0'; 683 684 if (tTd(33, 1)) 685 printf("crackaddr=>`%s'\n", buf); 686 687 return (buf); 688 } 689 /* 690 ** PUTHEADER -- put the header part of a message from the in-core copy 691 ** 692 ** Parameters: 693 ** fp -- file to put it on. 694 ** m -- mailer to use. 695 ** e -- envelope to use. 696 ** 697 ** Returns: 698 ** none. 699 ** 700 ** Side Effects: 701 ** none. 702 */ 703 704 /* 705 * Macro for fast max (not available in e.g. DG/UX, 386/ix). 706 */ 707 #ifndef MAX 708 # define MAX(a,b) (((a)>(b))?(a):(b)) 709 #endif 710 711 putheader(fp, m, e) 712 register FILE *fp; 713 register MAILER *m; 714 register ENVELOPE *e; 715 { 716 char buf[MAX(MAXLINE,BUFSIZ)]; 717 register HDR *h; 718 char obuf[MAXLINE]; 719 720 for (h = e->e_header; h != NULL; h = h->h_link) 721 { 722 register char *p; 723 extern bool bitintersect(); 724 725 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 726 !bitintersect(h->h_mflags, m->m_flags)) 727 continue; 728 729 /* handle Resent-... headers specially */ 730 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 731 continue; 732 733 p = h->h_value; 734 if (bitset(H_DEFAULT, h->h_flags)) 735 { 736 /* macro expand value if generated internally */ 737 expand(p, buf, &buf[sizeof buf], e); 738 p = buf; 739 if (p == NULL || *p == '\0') 740 continue; 741 } 742 743 if (bitset(H_FROM|H_RCPT, h->h_flags)) 744 { 745 /* address field */ 746 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 747 748 if (bitset(H_FROM, h->h_flags)) 749 oldstyle = FALSE; 750 commaize(h, p, fp, oldstyle, m, e); 751 } 752 else 753 { 754 /* vanilla header line */ 755 register char *nlp; 756 extern char *capitalize(); 757 758 (void) sprintf(obuf, "%s: ", capitalize(h->h_field)); 759 while ((nlp = strchr(p, '\n')) != NULL) 760 { 761 *nlp = '\0'; 762 (void) strcat(obuf, p); 763 *nlp = '\n'; 764 putline(obuf, fp, m); 765 p = ++nlp; 766 obuf[0] = '\0'; 767 } 768 (void) strcat(obuf, p); 769 putline(obuf, fp, m); 770 } 771 } 772 } 773 /* 774 ** COMMAIZE -- output a header field, making a comma-translated list. 775 ** 776 ** Parameters: 777 ** h -- the header field to output. 778 ** p -- the value to put in it. 779 ** fp -- file to put it to. 780 ** oldstyle -- TRUE if this is an old style header. 781 ** m -- a pointer to the mailer descriptor. If NULL, 782 ** don't transform the name at all. 783 ** e -- the envelope containing the message. 784 ** 785 ** Returns: 786 ** none. 787 ** 788 ** Side Effects: 789 ** outputs "p" to file "fp". 790 */ 791 792 commaize(h, p, fp, oldstyle, m, e) 793 register HDR *h; 794 register char *p; 795 FILE *fp; 796 bool oldstyle; 797 register MAILER *m; 798 register ENVELOPE *e; 799 { 800 register char *obp; 801 int opos; 802 bool firstone = TRUE; 803 char obuf[MAXLINE + 3]; 804 extern char *capitalize(); 805 806 /* 807 ** Output the address list translated by the 808 ** mailer and with commas. 809 */ 810 811 if (tTd(14, 2)) 812 printf("commaize(%s: %s)\n", h->h_field, p); 813 814 obp = obuf; 815 (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 816 opos = strlen(h->h_field) + 2; 817 obp += opos; 818 819 /* 820 ** Run through the list of values. 821 */ 822 823 while (*p != '\0') 824 { 825 register char *name; 826 register int c; 827 char savechar; 828 extern char *remotename(); 829 830 /* 831 ** Find the end of the name. New style names 832 ** end with a comma, old style names end with 833 ** a space character. However, spaces do not 834 ** necessarily delimit an old-style name -- at 835 ** signs mean keep going. 836 */ 837 838 /* find end of name */ 839 while ((isascii(*p) && isspace(*p)) || *p == ',') 840 p++; 841 name = p; 842 for (;;) 843 { 844 auto char *oldp; 845 char pvpbuf[PSBUFSIZE]; 846 extern char **prescan(); 847 848 (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp); 849 p = oldp; 850 851 /* look to see if we have an at sign */ 852 while (*p != '\0' && isascii(*p) && isspace(*p)) 853 p++; 854 855 if (*p != '@') 856 { 857 p = oldp; 858 break; 859 } 860 p += *p == '@' ? 1 : 2; 861 while (*p != '\0' && isascii(*p) && isspace(*p)) 862 p++; 863 } 864 /* at the end of one complete name */ 865 866 /* strip off trailing white space */ 867 while (p >= name && 868 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 869 p--; 870 if (++p == name) 871 continue; 872 savechar = *p; 873 *p = '\0'; 874 875 /* translate the name to be relative */ 876 name = remotename(name, m, bitset(H_FROM, h->h_flags), 877 TRUE, FALSE, TRUE, e); 878 if (*name == '\0') 879 { 880 *p = savechar; 881 continue; 882 } 883 884 /* output the name with nice formatting */ 885 opos += strlen(name); 886 if (!firstone) 887 opos += 2; 888 if (opos > 78 && !firstone) 889 { 890 (void) strcpy(obp, ",\n"); 891 putline(obuf, fp, m); 892 obp = obuf; 893 (void) sprintf(obp, " "); 894 opos = strlen(obp); 895 obp += opos; 896 opos += strlen(name); 897 } 898 else if (!firstone) 899 { 900 (void) sprintf(obp, ", "); 901 obp += 2; 902 } 903 904 /* strip off quote bits as we output */ 905 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 906 { 907 if (bitnset(M_7BITS, m->m_flags)) 908 c &= 0177; 909 *obp++ = c; 910 } 911 firstone = FALSE; 912 *p = savechar; 913 } 914 (void) strcpy(obp, "\n"); 915 putline(obuf, fp, m); 916 } 917 /* 918 ** COPYHEADER -- copy header list 919 ** 920 ** This routine is the equivalent of newstr for header lists 921 ** 922 ** Parameters: 923 ** header -- list of header structures to copy. 924 ** 925 ** Returns: 926 ** a copy of 'header'. 927 ** 928 ** Side Effects: 929 ** none. 930 */ 931 932 HDR * 933 copyheader(header) 934 register HDR *header; 935 { 936 register HDR *newhdr; 937 HDR *ret; 938 register HDR **tail = &ret; 939 940 while (header != NULL) 941 { 942 newhdr = (HDR *) xalloc(sizeof(HDR)); 943 STRUCTCOPY(*header, *newhdr); 944 *tail = newhdr; 945 tail = &newhdr->h_link; 946 header = header->h_link; 947 } 948 *tail = NULL; 949 950 return ret; 951 } 952