# 2.11BSD#431 - /usr/src/usr.sbin/sendmail.MX/src/headers.c

##### Functions

    addheader         X
    chompheader       X
    commaize          X
    crackaddr         X
    eatheader         X
    hvalue            X
    isatword          X
    isheader          X
    priencode         X
    putheader         X

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

#### Defined functions

addheader defined in line 176; used 3 times

- in /usr/src/usr.sbin/sendmail.MX/src/collect.c line 220
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 407-411(2)

chompheader defined in line 41; used 3 times

- in /usr/src/usr.sbin/sendmail.MX/src/collect.c line 135
- in /usr/src/usr.sbin/sendmail.MX/src/queue.c line 723
- in /usr/src/usr.sbin/sendmail.MX/src/readcf.c line 170

commaize defined in line 700; used 2 times

- in line 660
- in /usr/src/usr.sbin/sendmail.MX/src/queue.c line 223

crackaddr defined in line 464; used 3 times

- in line 53
- in /usr/src/usr.sbin/sendmail.MX/src/parseaddr.c line 1107, 1126

eatheader defined in line 283; used 3 times

- in /usr/src/usr.sbin/sendmail.MX/src/collect.c line 199
- in /usr/src/usr.sbin/sendmail.MX/src/queue.c line 642
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 428

hvalue defined in line 225; used 12 times

- in line 341, 350-355(2), 367, 374-381(3)
- in /usr/src/usr.sbin/sendmail.MX/src/collect.c line 49, 205-206(4)

isatword defined in line 839; used 2 times

- in line 754, 765

isheader defined in line 255; used 2 times

- in /usr/src/usr.sbin/sendmail.MX/src/collect.c line 96, 113

priencode defined in line 416; used 1 times

- in line 343

putheader defined in line 619; used 8 times

- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 46, 60
- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 113, 156
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 369, 399, 503, 512

#### Defined variables

sccsid defined in line 18; never used

Last modified: 1988-09-14 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2094 |