Annotation of 43BSDReno/usr.sbin/sendmail/src/headers.c, revision 1.1.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.