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

unix.superglobalmegacorp.com

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