home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / headers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-26  |  19.3 KB  |  945 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)headers.c    5.15 (Berkeley) 6/1/90";
  23. static char  rcsid[] = "@(#)$Id: headers.c,v 5.15.0.16 1991/06/26 21:43:28 paul Exp $";
  24. #endif /* not lint */
  25.  
  26. #include <sys/param.h>
  27. #include <errno.h>
  28. #include "sendmail.h"
  29.  
  30. #ifdef __STDC__
  31. static int priencode(const char *);
  32. static bool isatword(const char *);
  33. #else /* !__STDC__ */
  34. static int priencode();
  35. static bool isatword();
  36. #endif /* __STDC__ */
  37.  
  38. /*
  39. **  CHOMPHEADER -- process and save a header line.
  40. **
  41. **    Called by collect and by readcf to deal with header lines.
  42. **
  43. **    Parameters:
  44. **        line -- header as a text line.
  45. **        def -- if set, this is a default value.
  46. **
  47. **    Returns:
  48. **        flags for this header.
  49. **
  50. **    Side Effects:
  51. **        The header is saved on the header list.
  52. **        Contents of 'line' are destroyed.
  53. */
  54.  
  55. int
  56. chompheader(line, def)
  57.     char *line;
  58.     bool def;
  59. {
  60.     register char *p;
  61.     register HDR *h;
  62.     HDR **hp;
  63.     char *fname;
  64.     char *fvalue;
  65.     struct hdrinfo *hi;
  66.     bool cond = FALSE;
  67.     BITMAP mopts;
  68.  
  69.     if (tTd(31, 6))
  70.         printf("chompheader: %s\n", line);
  71.  
  72.     /* strip off options */
  73.     clrbitmap(mopts);
  74.     p = line;
  75.     if (*p == '?')
  76.     {
  77.         /* have some */
  78.         register char *q = index(p + 1, *p);
  79.         
  80.         if (q != NULL)
  81.         {
  82.             *q++ = '\0';
  83.             while (*++p != '\0')
  84.                 setbitn(*p, mopts);
  85.             p = q;
  86.         }
  87.         else
  88.             usrerr("chompheader: syntax error, line \"%s\"", line);
  89.         cond = TRUE;
  90.     }
  91.  
  92.     /* find canonical name */
  93.     fname = p;
  94.     p = index(p, ':');
  95.     if (p == NULL)
  96.     {
  97.         syserr("chompheader: syntax error, line \"%s\"", line);
  98.         return (0);
  99.     }
  100.     fvalue = &p[1];
  101.     while (isspace(*--p))
  102.         continue;
  103.     *++p = '\0';
  104.     makelower(fname);
  105.  
  106.     /* strip field value on front */
  107.     if (*fvalue == ' ')
  108.         fvalue++;
  109.  
  110.     /* see if it is a known type */
  111.     for (hi = HdrInfo; hi->hi_field != NULL; hi++)
  112.     {
  113.         if (strcmp(hi->hi_field, fname) == 0)
  114.             break;
  115.     }
  116.  
  117.     /* see if this is a resent message */
  118.     if (!def && bitset(H_RESENT, hi->hi_flags))
  119.         CurEnv->e_flags |= EF_RESENT;
  120.  
  121.     /* if this means "end of header" quit now */
  122.     if (bitset(H_EOH, hi->hi_flags))
  123.         return (hi->hi_flags);
  124.  
  125.     /* drop explicit From: if same as what we would generate -- for MH */
  126.     p = "resent-from";
  127.     if (!bitset(EF_RESENT, CurEnv->e_flags))
  128.         p += 7;
  129.     if (!def && !QueueRun && strcmp(fname, p) == 0)
  130.     {
  131.         if (CurEnv->e_from.q_paddr != NULL &&
  132.             strcmp(fvalue, CurEnv->e_from.q_paddr) == 0 &&
  133.             CurEnv->e_from.q_mailer == LocalMailer)
  134.             return (hi->hi_flags);
  135.     }
  136.  
  137.     /* delete default value for this header */
  138.     for (hp = &CurEnv->e_header; (h = *hp) != NULL; hp = &h->h_link)
  139.     {
  140.         if (strcmp(fname, h->h_field) == 0 &&
  141.             bitset(H_DEFAULT, h->h_flags) &&
  142.             !bitset(H_FORCE, h->h_flags))
  143.             h->h_value = NULL;
  144.     }
  145.  
  146.     /* create a new node */
  147.     h = (HDR *) xalloc(sizeof *h);
  148.     h->h_field = newstr(fname);
  149.     h->h_value = NULL;
  150.     h->h_link = NULL;
  151.     bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
  152.     *hp = h;
  153.     h->h_flags = hi->hi_flags;
  154.     if (def)
  155.         h->h_flags |= H_DEFAULT;
  156.     if (cond)
  157.         h->h_flags |= H_CHECK;
  158.     if (h->h_value != NULL)
  159.         free((char *) h->h_value);
  160.     h->h_value = newstr(fvalue);
  161.  
  162.     /* hack to see if this is a new format message */
  163.     if (!def && bitset(H_RCPT|H_FROM, h->h_flags) &&
  164.         (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL ||
  165.          index(fvalue, '<') != NULL || index(fvalue, ';') != NULL))
  166.     {
  167.         CurEnv->e_flags &= ~EF_OLDSTYLE;
  168.     }
  169.  
  170.     return (h->h_flags);
  171. }
  172. /*
  173. **  ADDHEADER -- add a header entry to the end of the queue.
  174. **
  175. **    This bypasses the special checking of chompheader.
  176. **
  177. **    Parameters:
  178. **        field -- the name of the header field.
  179. **        value -- the value of the field.  It must be lower-cased.
  180. **        e -- the envelope to add them to.
  181. **
  182. **    Returns:
  183. **        none.
  184. **
  185. **    Side Effects:
  186. **        adds the field on the list of headers for this envelope.
  187. */
  188.  
  189. void
  190. addheader(field, value, e)
  191.     char *field;
  192.     const char *value;
  193.     ENVELOPE *e;
  194. {
  195.     register HDR *h;
  196.     register struct hdrinfo *hi;
  197.     HDR **hp;
  198.  
  199.     /* find info struct */
  200.     for (hi = HdrInfo; hi->hi_field != NULL; hi++)
  201.     {
  202.         if (strcmp(field, hi->hi_field) == 0)
  203.             break;
  204.     }
  205.  
  206.     /* find current place in list -- keep back pointer? */
  207.     for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
  208.     {
  209.         if (strcmp(field, h->h_field) == 0)
  210.             break;
  211.     }
  212.  
  213.     /* allocate space for new header */
  214.     h = (HDR *) xalloc(sizeof *h);
  215.     h->h_field = field;
  216.     h->h_value = newstr(value);
  217.     h->h_link = *hp;
  218.     h->h_flags = hi->hi_flags | H_DEFAULT;
  219.     clrbitmap(h->h_mflags);
  220.     *hp = h;
  221. }
  222. /*
  223. **  HVALUE -- return value of a header.
  224. **
  225. **    Only "real" fields (i.e., ones that have not been supplied
  226. **    as a default) are used.
  227. **
  228. **    Parameters:
  229. **        field -- the field name.
  230. **
  231. **    Returns:
  232. **        pointer to the value part.
  233. **        NULL if not found.
  234. **
  235. **    Side Effects:
  236. **        none.
  237. */
  238.  
  239. char *
  240. hvalue(field)
  241.     const char *field;
  242. {
  243.     register HDR *h;
  244.  
  245.     for (h = CurEnv->e_header; h != NULL; h = h->h_link)
  246.     {
  247.         if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0)
  248.             return (h->h_value);
  249.     }
  250.     return (NULL);
  251. }
  252. /*
  253. **  FINDHEADER -- locate a specific header in the envelope
  254. **
  255. **    Parameters:
  256. **        field -- the name of the header field.
  257. **        e -- the envelope to search.
  258. **
  259. **    Returns:
  260. **        pointer to the header that matches.
  261. **        NULL if not found.
  262. **
  263. **    Side Effects:
  264. **        none.
  265. */
  266.  
  267. HDR *
  268. findheader(field, e)
  269.     const char *field;
  270.     ENVELOPE *e;
  271. {
  272.     register HDR *h;
  273.  
  274.     for (h = e->e_header; h != NULL; h = h->h_link)
  275.         if (h->h_field && strcmp(h->h_field, field) == 0)
  276.             return (h);
  277.     return (NULL);
  278. }
  279. /*
  280. **  ISHEADER -- predicate telling if argument is a header.
  281. **
  282. **    A line is a header if it has a single word followed by
  283. **    optional white space followed by a colon.
  284. **
  285. **    Parameters:
  286. **        s -- string to check for possible headerness.
  287. **
  288. **    Returns:
  289. **        TRUE if s is a header.
  290. **        FALSE otherwise.
  291. **
  292. **    Side Effects:
  293. **        none.
  294. */
  295.  
  296. bool
  297. isheader(s)
  298.     register const char *s;
  299. {
  300.     while (*s > ' ' && *s != ':' && *s != '\0')
  301.         s++;
  302.  
  303.     /* following technically violates RFC822 */
  304.     while (isspace(*s))
  305.         s++;
  306.  
  307.     return (*s == ':');
  308. }
  309. /*
  310. **  EATHEADER -- run through the stored header and extract info.
  311. **
  312. **    Parameters:
  313. **        e -- the envelope to process.
  314. **        tf -- file to append oversized headers to
  315. **
  316. **    Returns:
  317. **        none.
  318. **
  319. **    Side Effects:
  320. **        Sets a bunch of global variables from information
  321. **            in the collected header.
  322. **        Aborts the message if the hop count is exceeded.
  323. **        Appends oversized headers (> (MAXFIELD - 100) bytes)
  324. **            to end of message body.
  325. */
  326.  
  327. void
  328. eatheader(e, tf)
  329.     register ENVELOPE *e;
  330.     register FILE *tf;
  331. {
  332.     register HDR *h;
  333.     register char *p;
  334.     int hopcnt = 0;
  335.     bool ovfhdrs = 0;
  336.  
  337.     if (tTd(32, 1))
  338.         printf("----- collected header -----\n");
  339.     for (h = e->e_header; h != NULL; h = h->h_link)
  340.     {
  341.         if (tTd(32, 1))
  342.             printf("%s: %s\n", capitalize(h->h_field), h->h_value);
  343.         /* count the number of times it has been processed */
  344.         if (bitset(H_TRACE, h->h_flags))
  345.             hopcnt++;
  346.  
  347.         /* send to this person if we so desire */
  348.         if (GrabTo && bitset(H_RCPT, h->h_flags) &&
  349.             !bitset(H_DEFAULT, h->h_flags) &&
  350.             (!bitset(EF_RESENT, CurEnv->e_flags) || bitset(H_RESENT, h->h_flags)))
  351.         {
  352.             sendtolist(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
  353.         }
  354.  
  355.         if ((tf != NULL) && bitset(H_RCPT, h->h_flags) &&
  356.             !bitset(H_DEFAULT, h->h_flags) &&
  357.             (strlen(h->h_value) > (MAXFIELD - 100)))
  358.         {
  359.             bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
  360.  
  361.             if (!ovfhdrs)
  362.             {
  363.                 fputs("\n%%% overflow headers %%%\n", tf);
  364.                 ovfhdrs++;
  365.             }
  366.  
  367.             commaize(h, h->h_value, tf, oldstyle, LocalMailer);
  368.             /* two notes:
  369.              * (1) this upsets e_msgsize, but we don't care;
  370.              * (2) newstr() is needed since this is free()'d later
  371.              */
  372.             h->h_value =
  373.                 newstr("distribution:; (see end of body)");
  374.         }
  375.  
  376.         /* log the message-id */
  377. #ifdef LOG
  378.         if (!QueueRun && LogLevel > 8 && h->h_value != NULL &&
  379.             strcmp(h->h_field, "message-id") == 0)
  380.         {
  381.             char buf[MAXNAME];
  382.  
  383.             p = h->h_value;
  384.             if (bitset(H_DEFAULT, h->h_flags))
  385.             {
  386.                 expand(p, buf, &buf[(sizeof(buf)-1)], e);
  387.                 p = buf;
  388.             }
  389.             syslog(LOG_INFO, "%s: message-id=%s", e->e_id, p);
  390.         }
  391. #endif /* LOG */
  392.     }
  393.     if (tTd(32, 1))
  394.         printf("----------------------------\n");
  395.  
  396.     if (ovfhdrs)
  397.     {
  398.         fputs("%%% end overflow headers %%%\n", tf);
  399.     }
  400.  
  401.     /* store hop count */
  402.     if (hopcnt > e->e_hopcount)
  403.         e->e_hopcount = hopcnt;
  404.  
  405.     /* message priority */
  406.     p = hvalue("precedence");
  407.     if (p != NULL)
  408.         e->e_class = priencode(p);
  409.     if (!QueueRun)
  410.         e->e_msgpriority = e->e_msgsize
  411.                  - e->e_class * WkClassFact
  412.                  + e->e_nrcpts * WkRecipFact;
  413.  
  414.     /* return receipt to */
  415.     p = hvalue("return-receipt-to");
  416.     if (p != NULL)
  417.         e->e_receiptto = p;
  418.  
  419.     /* errors to */
  420.     p = hvalue("errors-to");
  421.     if (p != NULL)
  422.         sendtolist(p, (ADDRESS *) NULL, &e->e_errorqueue);
  423.  
  424.     /* from person */
  425.     if (OpMode == MD_ARPAFTP)
  426.     {
  427.         register struct hdrinfo *hi = HdrInfo;
  428.  
  429.         for (p = NULL; p == NULL && hi->hi_field != NULL; hi++)
  430.         {
  431.             if (bitset(H_FROM, hi->hi_flags))
  432.                 p = hvalue(hi->hi_field);
  433.         }
  434.         if (p != NULL)
  435.             setsender(p);
  436.     }
  437.  
  438.     /* full name of from person */
  439.     p = hvalue("full-name");
  440.     if (p != NULL)
  441.         define('x', p, e);
  442.  
  443.     /* date message originated */
  444.     p = hvalue("posted-date");
  445.     if (p == NULL)
  446.         p = hvalue("date");
  447.     if (p != NULL)
  448.     {
  449.         define('a', p, e);
  450.         if (p = arpatounix(p, e))
  451.         {
  452.             char *temp;
  453.  
  454.             p = newstr(p);
  455.             if ((temp = index(p, '\n')) != NULL)
  456.                 *temp = '\0';
  457.             define('d', p, e);
  458.         }
  459.     }
  460.  
  461.     /*
  462.     **  Log collection information.
  463.     */
  464.  
  465. #ifdef LOG
  466.     if (!QueueRun && LogLevel > 1)
  467.     {
  468.         char hbuf[100], *name = hbuf;
  469.  
  470.         if (RealHostName == NULL)
  471.         {
  472.             if ((name = macvalue('s', CurEnv)) == NULL)
  473.                 name = "local";
  474.         }
  475.         else if (RealHostName[0] == '[')
  476.             name = RealHostName;
  477.         else
  478.             (void)sprintf(hbuf, "%.90s (%s)", 
  479.                 RealHostName, inet_ntoa(RealHostAddr.sin_addr));
  480.         syslog(LOG_INFO,
  481.             "%s: from=%s, size=%ld, class=%d, received from %s",
  482.             CurEnv->e_id, CurEnv->e_from.q_paddr, CurEnv->e_msgsize,
  483.             CurEnv->e_class, name);
  484.     }
  485. #endif /* LOG */
  486. }
  487. /*
  488. **  PRIENCODE -- encode external priority names into internal values.
  489. **
  490. **    Parameters:
  491. **        p -- priority in ascii.
  492. **
  493. **    Returns:
  494. **        priority as a numeric level.
  495. **
  496. **    Side Effects:
  497. **        none.
  498. */
  499.  
  500. static int
  501. priencode(p)
  502.     const char *p;
  503. {
  504.     register int i;
  505.  
  506.     for (i = 0; i < NumPriorities; i++)
  507.     {
  508.         if (!strcasecmp(p, Priorities[i].pri_name))
  509.             return (Priorities[i].pri_val);
  510.     }
  511.  
  512.     /* unknown priority */
  513.     return (0);
  514. }
  515. /*
  516. **  CRACKADDR -- parse an address and turn it into a macro
  517. **
  518. **    This doesn't actually parse the address -- it just extracts
  519. **    it and replaces it with "$g".  The parse is totally ad hoc
  520. **    and isn't even guaranteed to leave something syntactically
  521. **    identical to what it started with.  However, it does leave
  522. **    something semantically identical.
  523. **
  524. **    The process is kind of strange.  There are a number of
  525. **    interesting cases:
  526. **        1.  comment <address> comment    ==> comment <$g> comment
  527. **        2.  address            ==> address
  528. **        3.  address (comment)        ==> $g (comment)
  529. **        4.  (comment) address        ==> (comment) $g
  530. **    And then there are the hard cases....
  531. **        5.  add (comment) ress        ==> $g (comment)
  532. **        6.  comment <address (comment)>    ==> comment <$g (comment)>
  533. **        7.    .... etc ....
  534. **
  535. **    Parameters:
  536. **        addr -- the address to be cracked.
  537. **
  538. **    Returns:
  539. **        a pointer to the new version.
  540. **
  541. **    Side Effects:
  542. **        none.
  543. **
  544. **    Warning:
  545. **        The return value is saved in local storage and should
  546. **        be copied if it is to be reused.
  547. */
  548.  
  549. char *
  550. crackaddr(addr)
  551.     register char *addr;
  552. {
  553.     register char *p;
  554.     register int i;
  555.     static char buf[MAXNAME];
  556.     char *rhs;
  557.     bool gotaddr;
  558.     register char *bp;
  559.  
  560.     if (tTd(33, 1))
  561.         printf("crackaddr(%s)\n", addr);
  562.  
  563.     (void) strcpy(buf, "");
  564.     rhs = NULL;
  565.  
  566.     /* strip leading spaces */
  567.     while (*addr != '\0' && isspace(*addr))
  568.         addr++;
  569.  
  570.     /*
  571.     **  See if we have anything in angle brackets.  If so, that is
  572.     **  the address part, and the rest is the comment.
  573.     */
  574.  
  575.     p = index(addr, '<');
  576.     if (p != NULL)
  577.     {
  578.         /* copy the beginning of the addr field to the buffer */
  579.         *p = '\0';
  580.         (void) strcpy(buf, addr);
  581.         (void) strcat(buf, "<");
  582.         *p++ = '<';
  583.  
  584.         /* skip spaces */
  585.         while (isspace(*p))
  586.             p++;
  587.  
  588.         /* find the matching right angle bracket */
  589.         addr = p;
  590.         for (i = 0; *p != '\0'; p++)
  591.         {
  592.             switch (*p)
  593.             {
  594.               case '<':
  595.                 i++;
  596.                 break;
  597.  
  598.               case '>':
  599.                 i--;
  600.                 break;
  601.             }
  602.             if (i < 0)
  603.                 break;
  604.         }
  605.  
  606.         /* p now points to the closing quote (or a null byte) */
  607.         if (*p != '\0')
  608.         {
  609.             /* make rhs point to the extra stuff at the end */
  610.             rhs = p;
  611.             *p++ = '\0';
  612.         }
  613.     }
  614.  
  615.     /*
  616.     **  Now parse the real address part.  "addr" points to the (null
  617.     **  terminated) version of what we are interested in; rhs points
  618.     **  to the extra stuff at the end of the line, if any.
  619.     */
  620.  
  621.     p = addr;
  622.  
  623.     /* now strip out comments */
  624.     bp = &buf[strlen(buf)];
  625.     gotaddr = FALSE;
  626.     for (; *p != '\0'; p++)
  627.     {
  628.         if (*p == '(')
  629.         {
  630.             /* copy to matching close paren */
  631.             *bp++ = *p++;
  632.             for (i = 0; *p != '\0'; p++)
  633.             {
  634.                 *bp++ = *p;
  635.                 switch (*p)
  636.                 {
  637.                   case '(':
  638.                     i++;
  639.                     break;
  640.  
  641.                   case ')':
  642.                     i--;
  643.                     break;
  644.                 }
  645.                 if (i < 0)
  646.                     break;
  647.             }
  648.             continue;
  649.         }
  650.  
  651.         /* keep semicolons */
  652.         if (*p == ';')
  653.             *bp++ = *p;
  654.  
  655.         /*
  656.         **  If this is the first "real" character we have seen,
  657.         **  then we put the "$g" in the buffer now.
  658.         */
  659.  
  660.         if (isspace(*p))
  661.             *bp++ = *p;
  662.         else if (!gotaddr)
  663.         {
  664.             (void) strcpy(bp, "\001g");
  665.             bp += 2;
  666.             gotaddr = TRUE;
  667.         }
  668.     }
  669.  
  670.     /* hack, hack.... strip trailing blanks */
  671.     do
  672.     {
  673.         *bp-- = '\0';
  674.     } while (isspace(*bp));
  675.     bp++;
  676.  
  677.     /* put any right hand side back on */
  678.     if (rhs != NULL)
  679.     {
  680.         *rhs = '>';
  681.         (void) strcpy(bp, rhs);
  682.     }
  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. void
  712. putheader(fp, m, e)
  713.     register FILE *fp;
  714.     register MAILER *m;
  715.     register ENVELOPE *e;
  716. {
  717.     char buf[MAX(MAXFIELD,BUFSIZ)];
  718.     register HDR *h;
  719.     char obuf[MAX(MAXFIELD,MAXLINE)];
  720.     char *macSvalue = macvalue('s', e);
  721.  
  722.     for (h = e->e_header; h != NULL; h = h->h_link)
  723.     {
  724.         register char *p;
  725.  
  726.         if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
  727.             !bitintersect(h->h_mflags, m->m_flags))
  728.             continue;
  729.  
  730.         /* handle Resent-... headers specially */
  731.         if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
  732.             continue;
  733.  
  734.         p = h->h_value;
  735.         if (bitset(H_DEFAULT, h->h_flags))
  736.         {
  737.             /*
  738.              * Use DeclHostName in headers that aren't H_RCPT
  739.              * or H_FROM.  Restore the original value after the
  740.              * expand().
  741.              */
  742.             if (!bitset(H_RCPT|H_FROM, h->h_flags) && DeclHostName)
  743.                 define('s', DeclHostName, e);
  744.  
  745.             /* macro expand value if generated internally */
  746.             expand(p, buf, &buf[(sizeof(buf)-1)], e);
  747.             if (!bitset(H_RCPT|H_FROM, h->h_flags) && DeclHostName)
  748.                 define('s', macSvalue, e);
  749.             p = buf;
  750.             if (p == NULL || *p == '\0')
  751.                 continue;
  752.         }
  753.  
  754.         if (bitset(H_FROM|H_RCPT, h->h_flags))
  755.         {
  756.             /* address field */
  757.             bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
  758.  
  759.             if (bitset(H_FROM, h->h_flags))
  760.                 oldstyle = FALSE;
  761.             commaize(h, p, fp, oldstyle, m);
  762.         }
  763.         else
  764.         {
  765.             /* vanilla header line */
  766.             register char *nlp;
  767.  
  768.             (void) sprintf(obuf, "%s: ", capitalize(h->h_field));
  769.             while ((nlp = index(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. **
  794. **    Returns:
  795. **        none.
  796. **
  797. **    Side Effects:
  798. **        outputs "p" to file "fp".
  799. */
  800.  
  801. void
  802. commaize(h, p, fp, oldstyle, m)
  803.     register HDR *h;
  804.     register char *p;
  805.     FILE *fp;
  806.     bool oldstyle;
  807.     register MAILER *m;
  808. {
  809.     register char *obp;
  810.     int opos;
  811.     bool firstone = TRUE;
  812.     char obuf[MAXLINE + 3];
  813.  
  814.     /*
  815.     **  Output the address list translated by the
  816.     **  mailer and with commas.
  817.     */
  818.  
  819.     if (tTd(14, 2))
  820.         printf("commaize(%s: %s)\n", h->h_field, p);
  821.  
  822.     obp = obuf;
  823.     (void) sprintf(obp, "%s: ", capitalize(h->h_field));
  824.     opos = strlen(h->h_field) + 2;
  825.     obp += opos;
  826.  
  827.     /*
  828.     **  Run through the list of values.
  829.     */
  830.  
  831.     while (*p != '\0')
  832.     {
  833.         register char *name;
  834.         char savechar;
  835.         extern char *DelimChar;        /* defined in prescan */
  836.  
  837.         /*
  838.         **  Find the end of the name.  New style names
  839.         **  end with a comma, old style names end with
  840.         **  a space character.  However, spaces do not
  841.         **  necessarily delimit an old-style name -- at
  842.         **  signs mean keep going.
  843.         */
  844.  
  845.         /* find end of name */
  846.         while (isspace(*p) || *p == ',')
  847.             p++;
  848.         name = p;
  849.         for (;;)
  850.         {
  851.             char *oldp;
  852.             char pvpbuf[PSBUFSIZE];
  853.  
  854.             (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf);
  855.             p = DelimChar;
  856.  
  857.             /* look to see if we have an at sign */
  858.             oldp = p;
  859.             while (*p != '\0' && isspace(*p))
  860.                 p++;
  861.  
  862.             if (*p != '@' && !isatword(p))
  863.             {
  864.                 p = oldp;
  865.                 break;
  866.             }
  867.             p += *p == '@' ? 1 : 2;
  868.             while (*p != '\0' && isspace(*p))
  869.                 p++;
  870.         }
  871.         /* at the end of one complete name */
  872.  
  873.         /* strip off trailing white space */
  874.         while (p >= name && (isspace(*p) || *p == ',' || *p == '\0'))
  875.             p--;
  876.         if (++p == name)
  877.             continue;
  878.         savechar = *p;
  879.         *p = '\0';
  880.  
  881.         /* translate the name to be relative */
  882.         name = remotename(name, m, bitset(H_FROM, h->h_flags), FALSE, TRUE);
  883.         if (*name == '\0')
  884.         {
  885.             *p = savechar;
  886.             continue;
  887.         }
  888.  
  889.         /* output the name with nice formatting */
  890.         opos += qstrlen(name);
  891.         if (!firstone)
  892.             opos += 2;
  893.         if (opos > 78 && !firstone)
  894.         {
  895.             (void) strcpy(obp, ",\n");
  896.             putline(obuf, fp, m);
  897.             obp = obuf;
  898.             (void) sprintf(obp, "        ");
  899.             opos = strlen(obp);
  900.             obp += opos;
  901.             opos += qstrlen(name);
  902.         }
  903.         else if (!firstone)
  904.         {
  905.             (void) sprintf(obp, ", ");
  906.             obp += 2;
  907.         }
  908.  
  909.         /* strip off quote bits as we output */
  910.         while (*name != '\0' && obp < &obuf[MAXLINE])
  911.         {
  912.             if (bitset(0200, *name))
  913.                 *obp++ = '\\';
  914.             *obp++ = *name++ & ~0200;
  915.         }
  916.         firstone = FALSE;
  917.         *p = savechar;
  918.     }
  919.     (void) strcpy(obp, "\n");
  920.     putline(obuf, fp, m);
  921. }
  922. /*
  923. **  ISATWORD -- tell if the word we are pointing to is "at".
  924. **
  925. **    Parameters:
  926. **        p -- word to check.
  927. **
  928. **    Returns:
  929. **        TRUE -- if p is the word at.
  930. **        FALSE -- otherwise.
  931. **
  932. **    Side Effects:
  933. **        none.
  934. */
  935.  
  936. static bool
  937. isatword(p)
  938.     register const char *p;
  939. {
  940.     if (lower(p[0]) == 'a' && lower(p[1]) == 't' &&
  941.         p[2] != '\0' && isspace(p[2]))
  942.         return (TRUE);
  943.     return (FALSE);
  944. }
  945.