122697Sdist /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
362522Sbostic * Copyright (c) 1988, 1993
462522Sbostic * The Regents of the University of California. All rights reserved.
533728Sbostic *
642824Sbostic * %sccs.include.redist.c%
733728Sbostic */
822697Sdist
922697Sdist #ifndef lint
10*69836Seric static char sccsid[] = "@(#)collect.c 8.44 (Berkeley) 06/10/95";
1133728Sbostic #endif /* not lint */
1222697Sdist
131439Seric # include <errno.h>
143309Seric # include "sendmail.h"
151392Seric
161392Seric /*
172969Seric ** COLLECT -- read & parse message header & make temp file.
181392Seric **
191392Seric ** Creates a temporary file name and copies the standard
209371Seric ** input to that file. Leading UNIX-style "From" lines are
219371Seric ** stripped off (after important information is extracted).
221392Seric **
231392Seric ** Parameters:
2467546Seric ** fp -- file to read.
2552106Seric ** smtpmode -- if set, we are running SMTP: give an RFC821
2652105Seric ** style message to say we are ready to collect
2752105Seric ** input, and never ignore a single dot to mean
2852105Seric ** end of message.
2958929Seric ** requeueflag -- this message will be requeued later, so
3058929Seric ** don't do final processing on it.
3167546Seric ** hdrp -- the location to stash the header.
3258929Seric ** e -- the current envelope.
331392Seric **
341392Seric ** Returns:
354162Seric ** none.
361392Seric **
371392Seric ** Side Effects:
381392Seric ** Temp file is created and filled.
394162Seric ** The from person may be set.
401392Seric */
411392Seric
4267599Seric static jmp_buf CtxCollectTimeout;
4368433Seric static void collecttimeout();
4467599Seric static bool CollectProgress;
4567599Seric static EVENT *CollectTimeout;
4667599Seric
4767599Seric /* values for input state machine */
4867599Seric #define IS_NORM 0 /* middle of line */
4967599Seric #define IS_BOL 1 /* beginning of line */
5067599Seric #define IS_DOT 2 /* read a dot at beginning of line */
5167599Seric #define IS_DOTCR 3 /* read ".\r" at beginning of line */
5267599Seric #define IS_CR 4 /* read a carriage return */
5367599Seric
5467599Seric /* values for message state machine */
5567599Seric #define MS_UFROM 0 /* reading Unix from line */
5667599Seric #define MS_HEADER 1 /* reading message header */
5767599Seric #define MS_BODY 2 /* reading message body */
5867599Seric
5968433Seric void
collect(fp,smtpmode,requeueflag,hdrp,e)6067546Seric collect(fp, smtpmode, requeueflag, hdrp, e)
6167546Seric FILE *fp;
6252105Seric bool smtpmode;
6358929Seric bool requeueflag;
6467546Seric HDR **hdrp;
6555012Seric register ENVELOPE *e;
661392Seric {
671392Seric register FILE *tf;
6852105Seric bool ignrdot = smtpmode ? FALSE : IgnrDot;
6967268Seric time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
7067599Seric register char *bp;
7168433Seric int c = '\0';
7264718Seric bool inputerr = FALSE;
7368717Seric bool headeronly;
7467599Seric char *buf;
7567599Seric int buflen;
7667599Seric int istate;
7767599Seric int mstate;
7867599Seric char *pbp;
7967599Seric char peekbuf[8];
8068564Seric char dfname[20];
8167599Seric char bufbuf[MAXLINE];
8267599Seric extern bool isheader();
8368433Seric extern void eatheader();
8468433Seric extern void tferror();
851392Seric
8668717Seric headeronly = hdrp != NULL;
8766796Seric
881392Seric /*
891392Seric ** Create the temp file name and create the file.
901392Seric */
911392Seric
9267546Seric if (!headeronly)
931392Seric {
9467617Seric struct stat stbuf;
9567617Seric
9668564Seric strcpy(dfname, queuename(e, 'd'));
9768564Seric if ((tf = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL)
9867546Seric {
9968564Seric syserr("Cannot create %s", dfname);
10068559Seric e->e_flags |= EF_NO_BODY_RETN;
10167546Seric finis();
10267546Seric }
10367617Seric if (fstat(fileno(tf), &stbuf) < 0)
10467617Seric e->e_dfino = -1;
10567617Seric else
10667688Seric {
10767688Seric e->e_dfdev = stbuf.st_dev;
10867617Seric e->e_dfino = stbuf.st_ino;
10967688Seric }
11067546Seric HasEightBits = FALSE;
11168560Seric e->e_msgsize = 0;
11268564Seric e->e_flags |= EF_HAS_DF;
1131392Seric }
1141392Seric
1154316Seric /*
1164322Seric ** Tell ARPANET to go ahead.
1174322Seric */
1184322Seric
11952105Seric if (smtpmode)
12058151Seric message("354 Enter mail, end with \".\" on a line by itself");
1214322Seric
12268717Seric if (tTd(30, 2))
12368717Seric printf("collect\n");
12468717Seric
1254322Seric /*
12667599Seric ** Read the message.
12767599Seric **
12867599Seric ** This is done using two interleaved state machines.
12967599Seric ** The input state machine is looking for things like
13067599Seric ** hidden dots; the message state machine is handling
13167599Seric ** the larger picture (e.g., header versus body).
1324316Seric */
1334316Seric
13467599Seric buf = bp = bufbuf;
13567599Seric buflen = sizeof bufbuf;
13667599Seric pbp = peekbuf;
13767599Seric istate = IS_BOL;
13867599Seric mstate = SaveFrom ? MS_HEADER : MS_UFROM;
13967599Seric CollectProgress = FALSE;
14067599Seric
14167599Seric if (dbto != 0)
1422900Seric {
14367599Seric /* handle possible input timeout */
14467599Seric if (setjmp(CtxCollectTimeout) != 0)
14567599Seric {
14667599Seric #ifdef LOG
14767599Seric syslog(LOG_NOTICE,
14867599Seric "timeout waiting for input from %s during message collect",
14967599Seric CurHostName ? CurHostName : "<local machine>");
15067599Seric #endif
15167599Seric errno = 0;
15267599Seric usrerr("451 timeout waiting for input during message collect");
15340965Sbostic goto readerr;
15467599Seric }
15567599Seric CollectTimeout = setevent(dbto, collecttimeout, dbto);
1562900Seric }
1572900Seric
15840965Sbostic for (;;)
1591392Seric {
16067599Seric if (tTd(30, 35))
16167599Seric printf("top, istate=%d, mstate=%d\n", istate, mstate);
16240965Sbostic for (;;)
1631392Seric {
16467599Seric if (pbp > peekbuf)
16567599Seric c = *--pbp;
16667599Seric else
16764916Seric {
16868717Seric while (!feof(fp) && !ferror(fp))
16967599Seric {
17067599Seric errno = 0;
17168877Seric c = getc(fp);
17267599Seric if (errno != EINTR)
17367599Seric break;
17468717Seric clearerr(fp);
17567599Seric }
17667599Seric CollectProgress = TRUE;
17768717Seric if (TrafficLogFile != NULL && !headeronly)
17867599Seric {
17967599Seric if (istate == IS_BOL)
18067599Seric fprintf(TrafficLogFile, "%05d <<< ",
18167599Seric getpid());
18267599Seric if (c == EOF)
18367599Seric fprintf(TrafficLogFile, "[EOF]\n");
18467599Seric else
18568877Seric putc(c, TrafficLogFile);
18667599Seric }
18767599Seric if (c == EOF)
18867599Seric goto readerr;
18967599Seric if (SevenBitInput)
19067599Seric c &= 0x7f;
19167599Seric else
19267599Seric HasEightBits |= bitset(0x80, c);
19368560Seric if (!headeronly)
19468560Seric e->e_msgsize++;
19567599Seric }
19667599Seric if (tTd(30, 94))
19767599Seric printf("istate=%d, c=%c (0x%x)\n",
19867599Seric istate, c, c);
19967599Seric switch (istate)
20067599Seric {
20167599Seric case IS_BOL:
20267599Seric if (c == '.')
20367599Seric {
20467599Seric istate = IS_DOT;
20567599Seric continue;
20667599Seric }
20764916Seric break;
20840965Sbostic
20967599Seric case IS_DOT:
21067599Seric if (c == '\n' && !ignrdot &&
21167599Seric !bitset(EF_NL_NOT_EOL, e->e_flags))
21267599Seric goto readerr;
21367599Seric else if (c == '\r' &&
21467599Seric !bitset(EF_CRLF_NOT_EOL, e->e_flags))
21567599Seric {
21667599Seric istate = IS_DOTCR;
21767599Seric continue;
21867599Seric }
21967599Seric else if (c != '.' ||
22067599Seric (OpMode != MD_SMTP &&
22167599Seric OpMode != MD_DAEMON &&
22267599Seric OpMode != MD_ARPAFTP))
22367599Seric {
22467599Seric *pbp++ = c;
22567599Seric c = '.';
22667599Seric }
2272900Seric break;
22840965Sbostic
22967599Seric case IS_DOTCR:
23067599Seric if (c == '\n')
23167599Seric goto readerr;
23267599Seric else
23367599Seric {
23467599Seric /* push back the ".\rx" */
23567599Seric *pbp++ = c;
23667599Seric *pbp++ = '\r';
23767599Seric c = '.';
23867599Seric }
23967599Seric break;
24040965Sbostic
24167599Seric case IS_CR:
24267689Seric if (c == '\n')
24367689Seric istate = IS_BOL;
24467689Seric else
24567599Seric {
24668717Seric ungetc(c, fp);
24767599Seric c = '\r';
24867689Seric istate = IS_NORM;
24967599Seric }
25067689Seric goto bufferchar;
25167599Seric }
25257135Seric
25367689Seric if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
25440965Sbostic {
25567599Seric istate = IS_CR;
25667599Seric continue;
25767599Seric }
25867599Seric else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
25967599Seric istate = IS_BOL;
26067599Seric else
26167599Seric istate = IS_NORM;
26240965Sbostic
26367689Seric bufferchar:
26467599Seric if (mstate == MS_BODY)
26567599Seric {
26667599Seric /* just put the character out */
26767831Seric if (MaxMessageSize <= 0 ||
26867831Seric e->e_msgsize <= MaxMessageSize)
26968877Seric putc(c, tf);
27067599Seric continue;
27140965Sbostic }
2721392Seric
27367599Seric /* header -- buffer up */
27467599Seric if (bp >= &buf[buflen - 2])
27567599Seric {
27667599Seric char *obuf;
2771392Seric
27867599Seric if (mstate != MS_HEADER)
27967599Seric break;
28040965Sbostic
28167599Seric /* out of space for header */
28267599Seric obuf = buf;
28367599Seric if (buflen < MEMCHUNKSIZE)
28467599Seric buflen *= 2;
28567599Seric else
28667599Seric buflen += MEMCHUNKSIZE;
28767599Seric buf = xalloc(buflen);
28867599Seric bcopy(obuf, buf, bp - obuf);
28967599Seric bp = &buf[bp - obuf];
29067599Seric if (obuf != bufbuf)
29167599Seric free(obuf);
29267599Seric }
29368738Seric if (c != '\0')
29468738Seric *bp++ = c;
29567599Seric if (istate == IS_BOL)
29667599Seric break;
29740965Sbostic }
29867599Seric *bp = '\0';
29940965Sbostic
30067599Seric nextstate:
30167599Seric if (tTd(30, 35))
30267599Seric printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
30367599Seric istate, mstate, buf);
30467599Seric switch (mstate)
30567599Seric {
30668433Seric extern int chompheader();
30768433Seric
30867599Seric case MS_UFROM:
30967599Seric mstate = MS_HEADER;
31067599Seric if (strncmp(buf, "From ", 5) == 0)
31167599Seric {
31268433Seric extern void eatfrom();
31368433Seric
31467704Seric bp = buf;
31567599Seric eatfrom(buf, e);
31667599Seric continue;
31767599Seric }
31867599Seric /* fall through */
3192900Seric
32067599Seric case MS_HEADER:
32167599Seric if (!isheader(buf))
32267599Seric {
32367599Seric mstate = MS_BODY;
32467599Seric goto nextstate;
32567599Seric }
32657135Seric
32767599Seric /* check for possible continuation line */
32867599Seric do
32967599Seric {
33068717Seric clearerr(fp);
33167599Seric errno = 0;
33268877Seric c = getc(fp);
33367599Seric } while (errno == EINTR);
33467599Seric if (c != EOF)
33568717Seric ungetc(c, fp);
33667599Seric if (c == ' ' || c == '\t')
33767599Seric {
33867599Seric /* yep -- defer this */
33967599Seric continue;
34067599Seric }
34157135Seric
34267599Seric /* trim off trailing CRLF or NL */
34367599Seric if (*--bp != '\n' || *--bp != '\r')
34467599Seric bp++;
34567599Seric *bp = '\0';
34668717Seric if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e)))
34767599Seric mstate = MS_BODY;
34867599Seric break;
3491392Seric
35067599Seric case MS_BODY:
35167599Seric if (tTd(30, 1))
35267599Seric printf("EOH\n");
35367599Seric if (headeronly)
35467599Seric goto readerr;
35567599Seric bp = buf;
3562900Seric
35767599Seric /* toss blank line */
35867599Seric if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
35967599Seric bp[0] == '\r' && bp[1] == '\n') ||
36067599Seric (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
36167599Seric bp[0] == '\n'))
36267599Seric {
36367599Seric break;
36467599Seric }
36567546Seric
36667599Seric /* if not a blank separator, write it out */
36767831Seric if (MaxMessageSize <= 0 ||
36867831Seric e->e_msgsize <= MaxMessageSize)
36967831Seric {
37067831Seric while (*bp != '\0')
37168877Seric putc(*bp++, tf);
37267831Seric }
3732900Seric break;
37467599Seric }
37567599Seric bp = buf;
37664718Seric }
37740965Sbostic
37867546Seric readerr:
37967546Seric if ((feof(fp) && smtpmode) || ferror(fp))
38064718Seric {
38169622Seric const char *errmsg = errstring(errno);
38269622Seric
38364916Seric if (tTd(30, 1))
38469622Seric printf("collect: premature EOM: %s\n", errmsg);
38569622Seric #ifdef LOG
38669622Seric if (LogLevel >= 2)
38769622Seric syslog(LOG_WARNING, "collect: premature EOM: %s", errmsg);
38869622Seric #endif
38964718Seric inputerr = TRUE;
39064718Seric }
39164718Seric
39266765Seric /* reset global timer */
39367599Seric clrevent(CollectTimeout);
39466765Seric
39567546Seric if (headeronly)
39667546Seric return;
39767546Seric
39867546Seric if (tf != NULL)
39964762Seric {
40067546Seric if (fflush(tf) != 0)
40167546Seric tferror(tf, e);
40267546Seric if (fsync(fileno(tf)) < 0 || fclose(tf) < 0)
40367546Seric {
40467546Seric tferror(tf, e);
40567546Seric finis();
40667546Seric }
40764762Seric }
4082900Seric
40968692Seric /* An EOF when running SMTP is an error */
41068692Seric if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
41116136Seric {
41258308Seric char *host;
41364718Seric char *problem;
41458082Seric
41558308Seric host = RealHostName;
41658308Seric if (host == NULL)
41758308Seric host = "localhost";
41858308Seric
41967546Seric if (feof(fp))
42064718Seric problem = "unexpected close";
42167546Seric else if (ferror(fp))
42264718Seric problem = "I/O error";
42364718Seric else
42464718Seric problem = "read timeout";
42536233Skarels # ifdef LOG
42667546Seric if (LogLevel > 0 && feof(fp))
42736230Skarels syslog(LOG_NOTICE,
42866864Seric "collect: %s on connection from %s, sender=%s: %s\n",
42966864Seric problem, host, e->e_from.q_paddr, errstring(errno));
43036233Skarels # endif
43167546Seric if (feof(fp))
43265951Seric usrerr("451 collect: %s on connection from %s, from=%s",
43364718Seric problem, host, e->e_from.q_paddr);
43465951Seric else
43565951Seric syserr("451 collect: %s on connection from %s, from=%s",
43665951Seric problem, host, e->e_from.q_paddr);
43711145Seric
43816136Seric /* don't return an error indication */
43955012Seric e->e_to = NULL;
44055012Seric e->e_flags &= ~EF_FATALERRS;
44164124Seric e->e_flags |= EF_CLRQUEUE;
44216136Seric
44316136Seric /* and don't try to deliver the partial message either */
44464718Seric if (InChild)
44564718Seric ExitStat = EX_QUIT;
44616136Seric finis();
44716136Seric }
44816136Seric
4492900Seric /*
4502900Seric ** Find out some information from the headers.
4513386Seric ** Examples are who is the from person & the date.
4522900Seric */
4532900Seric
45458929Seric eatheader(e, !requeueflag);
4557673Seric
456*69836Seric if (GrabTo && e->e_sendqueue == NULL)
457*69836Seric usrerr("No recipient addresses found in header");
458*69836Seric
45964068Seric /* collect statistics */
46064068Seric if (OpMode != MD_VERIFY)
46168433Seric {
46268433Seric extern void markstats();
46368433Seric
46464068Seric markstats(e, (ADDRESS *) NULL);
46568433Seric }
46664068Seric
4677782Seric /*
4687782Seric ** Add an Apparently-To: line if we have no recipient lines.
4697782Seric */
4704622Seric
47167546Seric if (hvalue("to", e->e_header) == NULL &&
47267546Seric hvalue("cc", e->e_header) == NULL &&
47367546Seric hvalue("bcc", e->e_header) == NULL &&
47467546Seric hvalue("apparently-to", e->e_header) == NULL)
4757367Seric {
4767367Seric register ADDRESS *q;
47768449Seric char *hdr = NULL;
47868449Seric extern void addheader();
4797367Seric
4807367Seric /* create an Apparently-To: field */
4817367Seric /* that or reject the message.... */
48268449Seric switch (NoRecipientAction)
4837367Seric {
48468449Seric case NRA_ADD_APPARENTLY_TO:
48568449Seric hdr = "Apparently-To";
48668449Seric break;
48768433Seric
48868449Seric case NRA_ADD_TO:
48968449Seric hdr = "To";
49068449Seric break;
49168449Seric
49268449Seric case NRA_ADD_BCC:
49368449Seric addheader("Bcc", "", &e->e_header);
49468449Seric break;
49568449Seric
49668449Seric case NRA_ADD_TO_UNDISCLOSED:
49768449Seric addheader("To", "undisclosed-recipients:;", &e->e_header);
49868449Seric break;
4997367Seric }
50068449Seric
50168449Seric if (hdr != NULL)
50268449Seric {
50368449Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next)
50468449Seric {
50568449Seric if (q->q_alias != NULL)
50668449Seric continue;
50768449Seric if (tTd(30, 3))
50868449Seric printf("Adding %s: %s\n",
50968449Seric hdr, q->q_paddr);
51068449Seric addheader(hdr, q->q_paddr, &e->e_header);
51168449Seric }
51268449Seric }
5137367Seric }
5147367Seric
51559320Seric /* check for message too large */
51659320Seric if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
51759320Seric {
51868857Seric e->e_status = "5.2.3";
51959320Seric usrerr("552 Message exceeds maximum fixed size (%ld)",
52059320Seric MaxMessageSize);
52169730Seric # ifdef LOG
52269730Seric if (LogLevel > 6)
52369730Seric syslog(LOG_NOTICE, "%s: message size (%ld) exceeds maximum (%ld)",
52469730Seric e->e_id, e->e_msgsize, MaxMessageSize);
52569730Seric # endif
52659320Seric }
52759320Seric
52867547Seric /* check for illegal 8-bit data */
52967547Seric if (HasEightBits)
53067547Seric {
53167547Seric e->e_flags |= EF_HAS8BIT;
53267887Seric if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode))
53368857Seric {
53468857Seric e->e_status = "5.6.1";
53567547Seric usrerr("554 Eight bit data not allowed");
53668857Seric }
53767547Seric }
53869105Seric else
53969105Seric {
54069105Seric /* if it claimed to be 8 bits, well, it lied.... */
54169105Seric if (e->e_bodytype != NULL &&
54269105Seric strcasecmp(e->e_bodytype, "8BITMIME") == 0)
54369105Seric e->e_bodytype = "7BIT";
54469105Seric }
54567547Seric
54668564Seric if ((e->e_dfp = fopen(dfname, "r")) == NULL)
54758690Seric {
54858690Seric /* we haven't acked receipt yet, so just chuck this */
54968564Seric syserr("Cannot reopen %s", dfname);
55058690Seric finis();
55158690Seric }
5521392Seric }
55340965Sbostic
55467599Seric
55568433Seric static void
collecttimeout(timeout)55667599Seric collecttimeout(timeout)
55767599Seric time_t timeout;
55840965Sbostic {
55967599Seric /* if no progress was made, die now */
56067599Seric if (!CollectProgress)
56167599Seric longjmp(CtxCollectTimeout, 1);
56240965Sbostic
56367599Seric /* otherwise reset the timeout */
56467599Seric CollectTimeout = setevent(timeout, collecttimeout, timeout);
56567599Seric CollectProgress = FALSE;
56640965Sbostic }
56740965Sbostic /*
56811544Seric ** TFERROR -- signal error on writing the temporary file.
56911544Seric **
57011544Seric ** Parameters:
57111544Seric ** tf -- the file pointer for the temporary file.
57268692Seric ** e -- the current envelope.
57311544Seric **
57411544Seric ** Returns:
57511544Seric ** none.
57611544Seric **
57711544Seric ** Side Effects:
57811544Seric ** Gives an error message.
57911544Seric ** Arranges for following output to go elsewhere.
58011544Seric */
58111544Seric
58268433Seric void
tferror(tf,e)58355012Seric tferror(tf, e)
58411544Seric FILE *tf;
58555012Seric register ENVELOPE *e;
58611544Seric {
58711544Seric if (errno == ENOSPC)
58811544Seric {
58966782Seric struct stat st;
59066782Seric long avail;
59166782Seric long bsize;
59266782Seric
59368559Seric e->e_flags |= EF_NO_BODY_RETN;
59466782Seric if (fstat(fileno(tf), &st) < 0)
59566782Seric st.st_size = 0;
59668564Seric (void) freopen(queuename(e, 'd'), "w", tf);
59766782Seric if (st.st_size <= 0)
59866782Seric fprintf(tf, "\n*** Mail could not be accepted");
59966782Seric else if (sizeof st.st_size > sizeof (long))
60066782Seric fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n",
60166782Seric st.st_size);
60266782Seric else
60366782Seric fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n",
60466782Seric st.st_size);
60566782Seric fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
60666782Seric MyHostName);
60769801Seric avail = freediskspace(QueueDir, &bsize);
60866782Seric if (avail > 0)
60966782Seric {
61066782Seric if (bsize > 1024)
61166782Seric avail *= bsize / 1024;
61266782Seric else if (bsize < 1024)
61366782Seric avail /= 1024 / bsize;
61466782Seric fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
61566782Seric avail);
61666782Seric }
61768857Seric e->e_status = "4.3.1";
61868692Seric usrerr("452 Out of disk space for temp file");
61911544Seric }
62011544Seric else
62168692Seric syserr("collect: Cannot write tf%s", e->e_id);
62211544Seric (void) freopen("/dev/null", "w", tf);
62311544Seric }
62411544Seric /*
6252900Seric ** EATFROM -- chew up a UNIX style from line and process
6262900Seric **
6272900Seric ** This does indeed make some assumptions about the format
6282900Seric ** of UNIX messages.
6292900Seric **
6302900Seric ** Parameters:
6312900Seric ** fm -- the from line.
6322900Seric **
6332900Seric ** Returns:
6342900Seric ** none.
6352900Seric **
6362900Seric ** Side Effects:
6372900Seric ** extracts what information it can from the header,
6383386Seric ** such as the date.
6392900Seric */
6402900Seric
6414321Seric # ifndef NOTUNIX
6424321Seric
6434203Seric char *DowList[] =
6444203Seric {
6454203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
6464203Seric };
6474203Seric
6482900Seric char *MonthList[] =
6492900Seric {
6502900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun",
6512900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
6522900Seric NULL
6532900Seric };
6542900Seric
65568433Seric void
eatfrom(fm,e)65655012Seric eatfrom(fm, e)
6572900Seric char *fm;
65855012Seric register ENVELOPE *e;
6592900Seric {
6602900Seric register char *p;
6612900Seric register char **dt;
6622900Seric
6637673Seric if (tTd(30, 2))
6644203Seric printf("eatfrom(%s)\n", fm);
6654203Seric
6662900Seric /* find the date part */
6672900Seric p = fm;
6682900Seric while (*p != '\0')
6692900Seric {
6702900Seric /* skip a word */
6712900Seric while (*p != '\0' && *p != ' ')
67216896Seric p++;
6732900Seric while (*p == ' ')
67416896Seric p++;
67558050Seric if (!(isascii(*p) && isupper(*p)) ||
67658050Seric p[3] != ' ' || p[13] != ':' || p[16] != ':')
6772900Seric continue;
6782900Seric
6792900Seric /* we have a possible date */
6804203Seric for (dt = DowList; *dt != NULL; dt++)
6812900Seric if (strncmp(*dt, p, 3) == 0)
6822900Seric break;
6834203Seric if (*dt == NULL)
6844203Seric continue;
6852900Seric
6864203Seric for (dt = MonthList; *dt != NULL; dt++)
6874203Seric if (strncmp(*dt, &p[4], 3) == 0)
6884203Seric break;
6892900Seric if (*dt != NULL)
6902900Seric break;
6912900Seric }
6922900Seric
69360502Seric if (*p != '\0')
6942900Seric {
6953386Seric char *q;
6965366Seric extern char *arpadate();
6973386Seric
6982900Seric /* we have found a date */
6993386Seric q = xalloc(25);
70023103Seric (void) strncpy(q, p, 25);
7013386Seric q[24] = '\0';
7025366Seric q = arpadate(q);
70355012Seric define('a', newstr(q), e);
7042900Seric }
7052900Seric }
7064321Seric
70756795Seric # endif /* NOTUNIX */
708