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.31 (Berkeley) 04/26/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 ** full -- if set, do full processing (e.g., compute 268 ** message priority). 269 ** 270 ** Returns: 271 ** none. 272 ** 273 ** Side Effects: 274 ** Sets a bunch of global variables from information 275 ** in the collected header. 276 ** Aborts the message if the hop count is exceeded. 277 */ 278 279 eatheader(e, full) 280 register ENVELOPE *e; 281 bool full; 282 { 283 register HDR *h; 284 register char *p; 285 int hopcnt = 0; 286 char *msgid; 287 char buf[MAXLINE]; 288 289 /* 290 ** Set up macros for possible expansion in headers. 291 */ 292 293 define('f', e->e_sender, e); 294 define('g', e->e_sender, e); 295 296 if (tTd(32, 1)) 297 printf("----- collected header -----\n"); 298 msgid = "<none>"; 299 for (h = e->e_header; h != NULL; h = h->h_link) 300 { 301 extern char *capitalize(); 302 303 /* do early binding */ 304 if (bitset(H_DEFAULT, h->h_flags) && h->h_value != NULL) 305 { 306 expand(h->h_value, buf, &buf[sizeof buf], e); 307 if (buf[0] != '\0') 308 { 309 h->h_value = newstr(buf); 310 h->h_flags &= ~H_DEFAULT; 311 } 312 } 313 314 if (tTd(32, 1)) 315 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 316 317 /* count the number of times it has been processed */ 318 if (bitset(H_TRACE, h->h_flags)) 319 hopcnt++; 320 321 /* send to this person if we so desire */ 322 if (GrabTo && bitset(H_RCPT, h->h_flags) && 323 !bitset(H_DEFAULT, h->h_flags) && 324 (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 325 { 326 (void) sendtolist(h->h_value, (ADDRESS *) NULL, 327 &e->e_sendqueue, e); 328 } 329 330 /* save the message-id for logging */ 331 if (full && h->h_value != NULL && 332 strcmp(h->h_field, "message-id") == 0) 333 { 334 msgid = h->h_value; 335 } 336 337 /* see if this is a return-receipt header */ 338 if (bitset(H_RECEIPTTO, h->h_flags)) 339 e->e_receiptto = h->h_value; 340 341 /* see if this is an errors-to header */ 342 if (bitset(H_ERRORSTO, h->h_flags)) 343 (void) sendtolist(h->h_value, (ADDRESS *) NULL, 344 &e->e_errorqueue, e); 345 } 346 if (tTd(32, 1)) 347 printf("----------------------------\n"); 348 349 /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 350 if (OpMode == MD_VERIFY) 351 return; 352 353 /* store hop count */ 354 if (hopcnt > e->e_hopcount) 355 e->e_hopcount = hopcnt; 356 357 /* message priority */ 358 p = hvalue("precedence", e); 359 if (p != NULL) 360 e->e_class = priencode(p); 361 if (full) 362 e->e_msgpriority = e->e_msgsize 363 - e->e_class * WkClassFact 364 + e->e_nrcpts * WkRecipFact; 365 366 /* full name of from person */ 367 p = hvalue("full-name", e); 368 if (p != NULL) 369 define('x', p, e); 370 371 /* date message originated */ 372 p = hvalue("posted-date", e); 373 if (p == NULL) 374 p = hvalue("date", e); 375 if (p != NULL) 376 define('a', p, e); 377 378 /* 379 ** Log collection information. 380 */ 381 382 # ifdef LOG 383 if (full && LogLevel > 4) 384 { 385 char *name; 386 char hbuf[MAXNAME]; 387 char sbuf[MAXLINE]; 388 extern char *macvalue(); 389 390 if (bitset(EF_RESPONSE, e->e_flags)) 391 name = "[RESPONSE]"; 392 else if ((name = macvalue('_', e)) != NULL) 393 ; 394 else if (RealHostName[0] == '[') 395 name = RealHostName; 396 else 397 { 398 extern char *anynet_ntoa(); 399 400 name = hbuf; 401 (void) sprintf(hbuf, "%.80s", RealHostName); 402 if (RealHostAddr.sa.sa_family != 0) 403 { 404 p = &hbuf[strlen(hbuf)]; 405 (void) sprintf(p, " (%s)", 406 anynet_ntoa(&RealHostAddr)); 407 } 408 } 409 410 /* some versions of syslog only take 5 printf args */ 411 sprintf(sbuf, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s", 412 e->e_from.q_paddr, e->e_msgsize, e->e_class, 413 e->e_msgpriority, e->e_nrcpts, msgid); 414 syslog(LOG_INFO, "%s: %s, relay=%s", 415 e->e_id, sbuf, name); 416 } 417 # endif /* LOG */ 418 } 419 /* 420 ** PRIENCODE -- encode external priority names into internal values. 421 ** 422 ** Parameters: 423 ** p -- priority in ascii. 424 ** 425 ** Returns: 426 ** priority as a numeric level. 427 ** 428 ** Side Effects: 429 ** none. 430 */ 431 432 priencode(p) 433 char *p; 434 { 435 register int i; 436 437 for (i = 0; i < NumPriorities; i++) 438 { 439 if (!strcasecmp(p, Priorities[i].pri_name)) 440 return (Priorities[i].pri_val); 441 } 442 443 /* unknown priority */ 444 return (0); 445 } 446 /* 447 ** CRACKADDR -- parse an address and turn it into a macro 448 ** 449 ** This doesn't actually parse the address -- it just extracts 450 ** it and replaces it with "$g". The parse is totally ad hoc 451 ** and isn't even guaranteed to leave something syntactically 452 ** identical to what it started with. However, it does leave 453 ** something semantically identical. 454 ** 455 ** This algorithm has been cleaned up to handle a wider range 456 ** of cases -- notably quoted and backslash escaped strings. 457 ** This modification makes it substantially better at preserving 458 ** the original syntax. 459 ** 460 ** Parameters: 461 ** addr -- the address to be cracked. 462 ** 463 ** Returns: 464 ** a pointer to the new version. 465 ** 466 ** Side Effects: 467 ** none. 468 ** 469 ** Warning: 470 ** The return value is saved in local storage and should 471 ** be copied if it is to be reused. 472 */ 473 474 char * 475 crackaddr(addr) 476 register char *addr; 477 { 478 register char *p; 479 register char c; 480 int cmtlev; 481 int realcmtlev; 482 int anglelev, realanglelev; 483 int copylev; 484 bool qmode; 485 bool realqmode; 486 bool skipping; 487 bool putgmac = FALSE; 488 bool quoteit = FALSE; 489 register char *bp; 490 char *buflim; 491 static char buf[MAXNAME]; 492 493 if (tTd(33, 1)) 494 printf("crackaddr(%s)\n", addr); 495 496 /* strip leading spaces */ 497 while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 498 addr++; 499 500 /* 501 ** Start by assuming we have no angle brackets. This will be 502 ** adjusted later if we find them. 503 */ 504 505 bp = buf; 506 buflim = &buf[sizeof buf - 5]; 507 p = addr; 508 copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 509 qmode = realqmode = FALSE; 510 511 while ((c = *p++) != '\0') 512 { 513 /* 514 ** If the buffer is overful, go into a special "skipping" 515 ** mode that tries to keep legal syntax but doesn't actually 516 ** output things. 517 */ 518 519 skipping = bp >= buflim; 520 521 if (copylev > 0 && !skipping) 522 *bp++ = c; 523 524 /* check for backslash escapes */ 525 if (c == '\\') 526 { 527 /* arrange to quote the address */ 528 if (cmtlev <= 0 && !qmode) 529 quoteit = TRUE; 530 531 if ((c = *p++) == '\0') 532 { 533 /* too far */ 534 p--; 535 goto putg; 536 } 537 if (copylev > 0 && !skipping) 538 *bp++ = c; 539 goto putg; 540 } 541 542 /* check for quoted strings */ 543 if (c == '"') 544 { 545 qmode = !qmode; 546 if (copylev > 0 && !skipping) 547 realqmode = !realqmode; 548 continue; 549 } 550 if (qmode) 551 goto putg; 552 553 /* check for comments */ 554 if (c == '(') 555 { 556 cmtlev++; 557 558 /* allow space for closing paren */ 559 if (!skipping) 560 { 561 buflim--; 562 realcmtlev++; 563 if (copylev++ <= 0) 564 { 565 *bp++ = ' '; 566 *bp++ = c; 567 } 568 } 569 } 570 if (cmtlev > 0) 571 { 572 if (c == ')') 573 { 574 cmtlev--; 575 copylev--; 576 if (!skipping) 577 { 578 realcmtlev--; 579 buflim++; 580 } 581 } 582 continue; 583 } 584 else if (c == ')') 585 { 586 /* syntax error: unmatched ) */ 587 if (!skipping) 588 bp--; 589 } 590 591 592 /* check for characters that may have to be quoted */ 593 if (strchr(".'@,;:\\()", c) != NULL) 594 { 595 /* 596 ** If these occur as the phrase part of a <> 597 ** construct, but are not inside of () or already 598 ** quoted, they will have to be quoted. Note that 599 ** now (but don't actually do the quoting). 600 */ 601 602 if (cmtlev <= 0 && !qmode) 603 quoteit = TRUE; 604 } 605 606 /* check for angle brackets */ 607 if (c == '<') 608 { 609 register char *q; 610 611 /* oops -- have to change our mind */ 612 anglelev++; 613 if (!skipping) 614 realanglelev++; 615 616 bp = buf; 617 if (quoteit) 618 { 619 *bp++ = '"'; 620 621 /* back up over the '<' and any spaces */ 622 --p; 623 while (isascii(*--p) && isspace(*p)) 624 continue; 625 p++; 626 } 627 for (q = addr; q < p; ) 628 { 629 c = *q++; 630 if (bp < buflim) 631 { 632 if (quoteit && c == '"') 633 *bp++ = '\\'; 634 *bp++ = c; 635 } 636 } 637 if (quoteit) 638 { 639 *bp++ = '"'; 640 while ((c = *p++) != '<') 641 { 642 if (bp < buflim) 643 *bp++ = c; 644 } 645 *bp++ = c; 646 } 647 copylev = 0; 648 putgmac = quoteit = FALSE; 649 continue; 650 } 651 652 if (c == '>') 653 { 654 if (anglelev > 0) 655 { 656 anglelev--; 657 if (!skipping) 658 { 659 realanglelev--; 660 buflim++; 661 } 662 } 663 else if (!skipping) 664 { 665 /* syntax error: unmatched > */ 666 if (copylev > 0) 667 bp--; 668 continue; 669 } 670 if (copylev++ <= 0) 671 *bp++ = c; 672 continue; 673 } 674 675 /* must be a real address character */ 676 putg: 677 if (copylev <= 0 && !putgmac) 678 { 679 *bp++ = MACROEXPAND; 680 *bp++ = 'g'; 681 putgmac = TRUE; 682 } 683 } 684 685 /* repair any syntactic damage */ 686 if (realqmode) 687 *bp++ = '"'; 688 while (realcmtlev-- > 0) 689 *bp++ = ')'; 690 while (realanglelev-- > 0) 691 *bp++ = '>'; 692 *bp++ = '\0'; 693 694 if (tTd(33, 1)) 695 printf("crackaddr=>`%s'\n", buf); 696 697 return (buf); 698 } 699 /* 700 ** PUTHEADER -- put the header part of a message from the in-core copy 701 ** 702 ** Parameters: 703 ** fp -- file to put it on. 704 ** m -- mailer to use. 705 ** e -- envelope to use. 706 ** 707 ** Returns: 708 ** none. 709 ** 710 ** Side Effects: 711 ** none. 712 */ 713 714 /* 715 * Macro for fast max (not available in e.g. DG/UX, 386/ix). 716 */ 717 #ifndef MAX 718 # define MAX(a,b) (((a)>(b))?(a):(b)) 719 #endif 720 721 putheader(fp, m, e) 722 register FILE *fp; 723 register MAILER *m; 724 register ENVELOPE *e; 725 { 726 char buf[MAX(MAXLINE,BUFSIZ)]; 727 register HDR *h; 728 char obuf[MAXLINE]; 729 730 for (h = e->e_header; h != NULL; h = h->h_link) 731 { 732 register char *p; 733 extern bool bitintersect(); 734 735 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 736 !bitintersect(h->h_mflags, m->m_flags)) 737 continue; 738 739 /* handle Resent-... headers specially */ 740 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 741 continue; 742 743 p = h->h_value; 744 if (bitset(H_DEFAULT, h->h_flags)) 745 { 746 /* macro expand value if generated internally */ 747 expand(p, buf, &buf[sizeof buf], e); 748 p = buf; 749 if (p == NULL || *p == '\0') 750 continue; 751 } 752 753 if (bitset(H_FROM|H_RCPT, h->h_flags)) 754 { 755 /* address field */ 756 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 757 758 if (bitset(H_FROM, h->h_flags)) 759 oldstyle = FALSE; 760 commaize(h, p, fp, oldstyle, m, e); 761 } 762 else 763 { 764 /* vanilla header line */ 765 register char *nlp; 766 extern char *capitalize(); 767 768 (void) sprintf(obuf, "%s: ", capitalize(h->h_field)); 769 while ((nlp = strchr(p, '\n')) != NULL) 770 { 771 *nlp = '\0'; 772 (void) strcat(obuf, p); 773 *nlp = '\n'; 774 putline(obuf, fp, m); 775 p = ++nlp; 776 obuf[0] = '\0'; 777 } 778 (void) strcat(obuf, p); 779 putline(obuf, fp, m); 780 } 781 } 782 } 783 /* 784 ** COMMAIZE -- output a header field, making a comma-translated list. 785 ** 786 ** Parameters: 787 ** h -- the header field to output. 788 ** p -- the value to put in it. 789 ** fp -- file to put it to. 790 ** oldstyle -- TRUE if this is an old style header. 791 ** m -- a pointer to the mailer descriptor. If NULL, 792 ** don't transform the name at all. 793 ** e -- the envelope containing the message. 794 ** 795 ** Returns: 796 ** none. 797 ** 798 ** Side Effects: 799 ** outputs "p" to file "fp". 800 */ 801 802 commaize(h, p, fp, oldstyle, m, e) 803 register HDR *h; 804 register char *p; 805 FILE *fp; 806 bool oldstyle; 807 register MAILER *m; 808 register ENVELOPE *e; 809 { 810 register char *obp; 811 int opos; 812 bool firstone = TRUE; 813 char obuf[MAXLINE + 3]; 814 extern char *capitalize(); 815 816 /* 817 ** Output the address list translated by the 818 ** mailer and with commas. 819 */ 820 821 if (tTd(14, 2)) 822 printf("commaize(%s: %s)\n", h->h_field, p); 823 824 obp = obuf; 825 (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 826 opos = strlen(h->h_field) + 2; 827 obp += opos; 828 829 /* 830 ** Run through the list of values. 831 */ 832 833 while (*p != '\0') 834 { 835 register char *name; 836 register int c; 837 char savechar; 838 int flags; 839 auto int stat; 840 extern char *remotename(); 841 842 /* 843 ** Find the end of the name. New style names 844 ** end with a comma, old style names end with 845 ** a space character. However, spaces do not 846 ** necessarily delimit an old-style name -- at 847 ** signs mean keep going. 848 */ 849 850 /* find end of name */ 851 while ((isascii(*p) && isspace(*p)) || *p == ',') 852 p++; 853 name = p; 854 for (;;) 855 { 856 auto char *oldp; 857 char pvpbuf[PSBUFSIZE]; 858 extern char **prescan(); 859 860 (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp); 861 p = oldp; 862 863 /* look to see if we have an at sign */ 864 while (*p != '\0' && isascii(*p) && isspace(*p)) 865 p++; 866 867 if (*p != '@') 868 { 869 p = oldp; 870 break; 871 } 872 p += *p == '@' ? 1 : 2; 873 while (*p != '\0' && isascii(*p) && isspace(*p)) 874 p++; 875 } 876 /* at the end of one complete name */ 877 878 /* strip off trailing white space */ 879 while (p >= name && 880 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 881 p--; 882 if (++p == name) 883 continue; 884 savechar = *p; 885 *p = '\0'; 886 887 /* translate the name to be relative */ 888 flags = RF_HEADERADDR|RF_ADDDOMAIN; 889 if (bitset(H_FROM, h->h_flags)) 890 flags |= RF_SENDERADDR; 891 stat = EX_OK; 892 name = remotename(name, m, flags, &stat, e); 893 if (*name == '\0') 894 { 895 *p = savechar; 896 continue; 897 } 898 899 /* output the name with nice formatting */ 900 opos += strlen(name); 901 if (!firstone) 902 opos += 2; 903 if (opos > 78 && !firstone) 904 { 905 (void) strcpy(obp, ",\n"); 906 putline(obuf, fp, m); 907 obp = obuf; 908 (void) sprintf(obp, " "); 909 opos = strlen(obp); 910 obp += opos; 911 opos += strlen(name); 912 } 913 else if (!firstone) 914 { 915 (void) sprintf(obp, ", "); 916 obp += 2; 917 } 918 919 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 920 *obp++ = c; 921 firstone = FALSE; 922 *p = savechar; 923 } 924 (void) strcpy(obp, "\n"); 925 putline(obuf, fp, m); 926 } 927 /* 928 ** COPYHEADER -- copy header list 929 ** 930 ** This routine is the equivalent of newstr for header lists 931 ** 932 ** Parameters: 933 ** header -- list of header structures to copy. 934 ** 935 ** Returns: 936 ** a copy of 'header'. 937 ** 938 ** Side Effects: 939 ** none. 940 */ 941 942 HDR * 943 copyheader(header) 944 register HDR *header; 945 { 946 register HDR *newhdr; 947 HDR *ret; 948 register HDR **tail = &ret; 949 950 while (header != NULL) 951 { 952 newhdr = (HDR *) xalloc(sizeof(HDR)); 953 STRUCTCOPY(*header, *newhdr); 954 *tail = newhdr; 955 tail = &newhdr->h_link; 956 header = header->h_link; 957 } 958 *tail = NULL; 959 960 return ret; 961 } 962