Annotation of 43BSDReno/usr.sbin/sendmail/src/headers.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.