Annotation of 43BSDReno/usr.sbin/sendmail/src/collect.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[] = "@(#)collect.c  5.9 (Berkeley) 6/1/90";
                     23: #endif /* not lint */
                     24: 
                     25: # include <errno.h>
                     26: # include "sendmail.h"
                     27: 
                     28: /*
                     29: **  COLLECT -- read & parse message header & make temp file.
                     30: **
                     31: **     Creates a temporary file name and copies the standard
                     32: **     input to that file.  Leading UNIX-style "From" lines are
                     33: **     stripped off (after important information is extracted).
                     34: **
                     35: **     Parameters:
                     36: **             sayok -- if set, give an ARPANET style message
                     37: **                     to say we are ready to collect input.
                     38: **
                     39: **     Returns:
                     40: **             none.
                     41: **
                     42: **     Side Effects:
                     43: **             Temp file is created and filled.
                     44: **             The from person may be set.
                     45: */
                     46: 
                     47: collect(sayok)
                     48:        bool sayok;
                     49: {
                     50:        register FILE *tf;
                     51:        char buf[MAXFIELD], buf2[MAXFIELD];
                     52:        register char *workbuf, *freebuf;
                     53:        register int workbuflen;
                     54:        extern char *hvalue();
                     55:        extern bool isheader(), flusheol();
                     56: 
                     57:        /*
                     58:        **  Create the temp file name and create the file.
                     59:        */
                     60: 
                     61:        CurEnv->e_df = newstr(queuename(CurEnv, 'd'));
                     62:        if ((tf = dfopen(CurEnv->e_df, "w")) == NULL)
                     63:        {
                     64:                syserr("Cannot create %s", CurEnv->e_df);
                     65:                NoReturn = TRUE;
                     66:                finis();
                     67:        }
                     68:        (void) chmod(CurEnv->e_df, FileMode);
                     69: 
                     70:        /*
                     71:        **  Tell ARPANET to go ahead.
                     72:        */
                     73: 
                     74:        if (sayok)
                     75:                message("354", "Enter mail, end with \".\" on a line by itself");
                     76: 
                     77:        /*
                     78:        **  Try to read a UNIX-style From line
                     79:        */
                     80: 
                     81:        if (sfgets(buf, MAXFIELD, InChannel) == NULL)
                     82:                goto readerr;
                     83:        fixcrlf(buf, FALSE);
                     84: # ifndef NOTUNIX
                     85:        if (!SaveFrom && strncmp(buf, "From ", 5) == 0)
                     86:        {
                     87:                if (!flusheol(buf, InChannel))
                     88:                        goto readerr;
                     89:                eatfrom(buf);
                     90:                if (sfgets(buf, MAXFIELD, InChannel) == NULL)
                     91:                        goto readerr;
                     92:                fixcrlf(buf, FALSE);
                     93:        }
                     94: # endif NOTUNIX
                     95: 
                     96:        /*
                     97:        **  Copy InChannel to temp file & do message editing.
                     98:        **      To keep certain mailers from getting confused,
                     99:        **      and to keep the output clean, lines that look
                    100:        **      like UNIX "From" lines are deleted in the header.
                    101:        */
                    102: 
                    103:        workbuf = buf;          /* `workbuf' contains a header field */
                    104:        freebuf = buf2;         /* `freebuf' can be used for read-ahead */
                    105:        for (;;)
                    106:        {
                    107:                /* first, see if the header is over */
                    108:                if (!isheader(workbuf))
                    109:                {
                    110:                        fixcrlf(workbuf, TRUE);
                    111:                        break;
                    112:                }
                    113: 
                    114:                /* if the line is too long, throw the rest away */
                    115:                if (!flusheol(workbuf, InChannel))
                    116:                        goto readerr;
                    117: 
                    118:                /* it's okay to toss '\n' now (flusheol() needed it) */
                    119:                fixcrlf(workbuf, TRUE);
                    120: 
                    121:                workbuflen = strlen(workbuf);
                    122: 
                    123:                /* get the rest of this field */
                    124:                for (;;)
                    125:                {
                    126:                        if (sfgets(freebuf, MAXFIELD, InChannel) == NULL)
                    127:                                goto readerr;
                    128: 
                    129:                        /* is this a continuation line? */
                    130:                        if (*freebuf != ' ' && *freebuf != '\t')
                    131:                                break;
                    132: 
                    133:                        if (!flusheol(freebuf, InChannel))
                    134:                                goto readerr;
                    135: 
                    136:                        /* yes; append line to `workbuf' if there's room */
                    137:                        if (workbuflen < MAXFIELD-3)
                    138:                        {
                    139:                                register char *p = workbuf + workbuflen;
                    140:                                register char *q = freebuf;
                    141: 
                    142:                                /* we have room for more of this field */
                    143:                                fixcrlf(freebuf, TRUE);
                    144:                                *p++ = '\n'; workbuflen++;
                    145:                                while(*q != '\0' && workbuflen < MAXFIELD-1)
                    146:                                {
                    147:                                        *p++ = *q++;
                    148:                                        workbuflen++;
                    149:                                }
                    150:                                *p = '\0';
                    151:                        }
                    152:                }
                    153: 
                    154:                CurEnv->e_msgsize += workbuflen;
                    155: 
                    156:                /*
                    157:                **  The working buffer now becomes the free buffer, since
                    158:                **  the free buffer contains a new header field.
                    159:                **
                    160:                **  This is premature, since we still havent called
                    161:                **  chompheader() to process the field we just created
                    162:                **  (so the call to chompheader() will use `freebuf').
                    163:                **  This convolution is necessary so that if we break out
                    164:                **  of the loop due to H_EOH, `workbuf' will always be
                    165:                **  the next unprocessed buffer.
                    166:                */
                    167: 
                    168:                {
                    169:                        register char *tmp = workbuf;
                    170:                        workbuf = freebuf;
                    171:                        freebuf = tmp;
                    172:                }
                    173: 
                    174:                /*
                    175:                **  Snarf header away.
                    176:                */
                    177: 
                    178:                if (bitset(H_EOH, chompheader(freebuf, FALSE)))
                    179:                        break;
                    180:        }
                    181: 
                    182:        if (tTd(30, 1))
                    183:                printf("EOH\n");
                    184: 
                    185:        if (*workbuf == '\0')
                    186:        {
                    187:                /* throw away a blank line */
                    188:                if (sfgets(buf, MAXFIELD, InChannel) == NULL)
                    189:                        goto readerr;
                    190:        }
                    191:        else if (workbuf == buf2)       /* guarantee `buf' contains data */
                    192:                (void) strcpy(buf, buf2);
                    193: 
                    194:        /*
                    195:        **  Collect the body of the message.
                    196:        */
                    197: 
                    198:        do
                    199:        {
                    200:                register char *bp = buf;
                    201: 
                    202:                fixcrlf(buf, TRUE);
                    203: 
                    204:                /* check for end-of-message */
                    205:                if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
                    206:                        break;
                    207: 
                    208:                /* check for transparent dot */
                    209:                if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.')
                    210:                        bp++;
                    211: 
                    212:                /*
                    213:                **  Figure message length, output the line to the temp
                    214:                **  file, and insert a newline if missing.
                    215:                */
                    216: 
                    217:                CurEnv->e_msgsize += strlen(bp) + 1;
                    218:                fputs(bp, tf);
                    219:                fputs("\n", tf);
                    220:                if (ferror(tf))
                    221:                        tferror(tf);
                    222:        } while (sfgets(buf, MAXFIELD, InChannel) != NULL);
                    223: 
                    224: readerr:
                    225:        if (fflush(tf) != 0)
                    226:                tferror(tf);
                    227:        (void) fclose(tf);
                    228: 
                    229:        /* An EOF when running SMTP is an error */
                    230:        if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP)
                    231:        {
                    232:                int usrerr(), syserr();
                    233: # ifdef LOG
                    234:                if (RealHostName != NULL && LogLevel > 0)
                    235:                        syslog(LOG_NOTICE,
                    236:                            "collect: unexpected close on connection from %s: %m\n",
                    237:                            CurEnv->e_from.q_paddr, RealHostName);
                    238: # endif
                    239:                (feof(InChannel) ? usrerr: syserr)
                    240:                        ("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr);
                    241: 
                    242:                /* don't return an error indication */
                    243:                CurEnv->e_to = NULL;
                    244:                CurEnv->e_flags &= ~EF_FATALERRS;
                    245: 
                    246:                /* and don't try to deliver the partial message either */
                    247:                finis();
                    248:        }
                    249: 
                    250:        /*
                    251:        **  Find out some information from the headers.
                    252:        **      Examples are who is the from person & the date.
                    253:        */
                    254: 
                    255:        eatheader(CurEnv);
                    256: 
                    257:        /*
                    258:        **  Add an Apparently-To: line if we have no recipient lines.
                    259:        */
                    260: 
                    261:        if (hvalue("to") == NULL && hvalue("cc") == NULL &&
                    262:            hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
                    263:        {
                    264:                register ADDRESS *q;
                    265: 
                    266:                /* create an Apparently-To: field */
                    267:                /*    that or reject the message.... */
                    268:                for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
                    269:                {
                    270:                        if (q->q_alias != NULL)
                    271:                                continue;
                    272:                        if (tTd(30, 3))
                    273:                                printf("Adding Apparently-To: %s\n", q->q_paddr);
                    274:                        addheader("apparently-to", q->q_paddr, CurEnv);
                    275:                }
                    276:        }
                    277: 
                    278:        if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL)
                    279:                syserr("Cannot reopen %s", CurEnv->e_df);
                    280: }
                    281: /*
                    282: **  FLUSHEOL -- if not at EOL, throw away rest of input line.
                    283: **
                    284: **     Parameters:
                    285: **             buf -- last line read in (checked for '\n'),
                    286: **             fp -- file to be read from.
                    287: **
                    288: **     Returns:
                    289: **             FALSE on error from sfgets(), TRUE otherwise.
                    290: **
                    291: **     Side Effects:
                    292: **             none.
                    293: */
                    294: 
                    295: bool
                    296: flusheol(buf, fp)
                    297:        char *buf;
                    298:        FILE *fp;
                    299: {
                    300:        char junkbuf[MAXLINE], *sfgets();
                    301:        register char *p = buf;
                    302: 
                    303:        while (index(p, '\n') == NULL) {
                    304:                if (sfgets(junkbuf,MAXLINE,fp) == NULL)
                    305:                        return(FALSE);
                    306:                p = junkbuf;
                    307:        }
                    308: 
                    309:        return(TRUE);
                    310: }
                    311: /*
                    312: **  TFERROR -- signal error on writing the temporary file.
                    313: **
                    314: **     Parameters:
                    315: **             tf -- the file pointer for the temporary file.
                    316: **
                    317: **     Returns:
                    318: **             none.
                    319: **
                    320: **     Side Effects:
                    321: **             Gives an error message.
                    322: **             Arranges for following output to go elsewhere.
                    323: */
                    324: 
                    325: tferror(tf)
                    326:        FILE *tf;
                    327: {
                    328:        if (errno == ENOSPC)
                    329:        {
                    330:                (void) freopen(CurEnv->e_df, "w", tf);
                    331:                fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
                    332:                usrerr("452 Out of disk space for temp file");
                    333:        }
                    334:        else
                    335:                syserr("collect: Cannot write %s", CurEnv->e_df);
                    336:        (void) freopen("/dev/null", "w", tf);
                    337: }
                    338: /*
                    339: **  EATFROM -- chew up a UNIX style from line and process
                    340: **
                    341: **     This does indeed make some assumptions about the format
                    342: **     of UNIX messages.
                    343: **
                    344: **     Parameters:
                    345: **             fm -- the from line.
                    346: **
                    347: **     Returns:
                    348: **             none.
                    349: **
                    350: **     Side Effects:
                    351: **             extracts what information it can from the header,
                    352: **             such as the date.
                    353: */
                    354: 
                    355: # ifndef NOTUNIX
                    356: 
                    357: char   *DowList[] =
                    358: {
                    359:        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
                    360: };
                    361: 
                    362: char   *MonthList[] =
                    363: {
                    364:        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                    365:        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
                    366:        NULL
                    367: };
                    368: 
                    369: eatfrom(fm)
                    370:        char *fm;
                    371: {
                    372:        register char *p;
                    373:        register char **dt;
                    374: 
                    375:        if (tTd(30, 2))
                    376:                printf("eatfrom(%s)\n", fm);
                    377: 
                    378:        /* find the date part */
                    379:        p = fm;
                    380:        while (*p != '\0')
                    381:        {
                    382:                /* skip a word */
                    383:                while (*p != '\0' && *p != ' ')
                    384:                        p++;
                    385:                while (*p == ' ')
                    386:                        p++;
                    387:                if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
                    388:                        continue;
                    389: 
                    390:                /* we have a possible date */
                    391:                for (dt = DowList; *dt != NULL; dt++)
                    392:                        if (strncmp(*dt, p, 3) == 0)
                    393:                                break;
                    394:                if (*dt == NULL)
                    395:                        continue;
                    396: 
                    397:                for (dt = MonthList; *dt != NULL; dt++)
                    398:                        if (strncmp(*dt, &p[4], 3) == 0)
                    399:                                break;
                    400:                if (*dt != NULL)
                    401:                        break;
                    402:        }
                    403: 
                    404:        if (*p != NULL)
                    405:        {
                    406:                char *q;
                    407:                extern char *arpadate();
                    408: 
                    409:                /* we have found a date */
                    410:                q = xalloc(25);
                    411:                (void) strncpy(q, p, 25);
                    412:                q[24] = '\0';
                    413:                define('d', q, CurEnv);
                    414:                q = arpadate(q);
                    415:                define('a', newstr(q), CurEnv);
                    416:        }
                    417: }
                    418: 
                    419: # endif NOTUNIX

unix.superglobalmegacorp.com

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