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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1983 Eric P. Allman
        !             3:  * Copyright (c) 1988 Regents of the University of California.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms are permitted provided
        !             7:  * that: (1) source distributions retain this entire copyright notice and
        !             8:  * comment, and (2) distributions including binaries display the following
        !             9:  * acknowledgement:  ``This product includes software developed by the
        !            10:  * University of California, Berkeley and its contributors'' in the
        !            11:  * documentation or other materials provided with the distribution and in
        !            12:  * all advertising materials mentioning features or use of this software.
        !            13:  * Neither the name of the University nor the names of its contributors may
        !            14:  * be used to endorse or promote products derived from this software without
        !            15:  * specific prior written permission.
        !            16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            19:  */
        !            20: 
        !            21: #ifndef lint
        !            22: static char sccsid[] = "@(#)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.