122697Sdist /* 234920Sbostic * Copyright (c) 1983 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*67617Seric static char sccsid[] = "@(#)collect.c 8.20 (Berkeley) 08/07/94"; 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 4266796Seric char *CollectErrorMessage; 4366796Seric bool CollectErrno; 4466796Seric 4567599Seric static jmp_buf CtxCollectTimeout; 4667599Seric static int collecttimeout(); 4767599Seric static bool CollectProgress; 4867599Seric static EVENT *CollectTimeout; 4967599Seric 5067599Seric /* values for input state machine */ 5167599Seric #define IS_NORM 0 /* middle of line */ 5267599Seric #define IS_BOL 1 /* beginning of line */ 5367599Seric #define IS_DOT 2 /* read a dot at beginning of line */ 5467599Seric #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 5567599Seric #define IS_CR 4 /* read a carriage return */ 5667599Seric 5767599Seric /* values for message state machine */ 5867599Seric #define MS_UFROM 0 /* reading Unix from line */ 5967599Seric #define MS_HEADER 1 /* reading message header */ 6067599Seric #define MS_BODY 2 /* reading message body */ 6167599Seric 6267599Seric 6367546Seric collect(fp, smtpmode, requeueflag, hdrp, e) 6467546Seric FILE *fp; 6552105Seric bool smtpmode; 6658929Seric bool requeueflag; 6767546Seric HDR **hdrp; 6855012Seric register ENVELOPE *e; 691392Seric { 701392Seric register FILE *tf; 7152105Seric bool ignrdot = smtpmode ? FALSE : IgnrDot; 7267268Seric time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; 7367599Seric register char *bp; 7467599Seric register int c; 7564718Seric bool inputerr = FALSE; 7667546Seric bool headeronly = FALSE; 7767599Seric char *buf; 7867599Seric int buflen; 7967599Seric int istate; 8067599Seric int mstate; 8167599Seric char *pbp; 8267599Seric char peekbuf[8]; 8367599Seric char bufbuf[MAXLINE]; 842900Seric extern char *hvalue(); 8567599Seric extern bool isheader(); 861392Seric 8766796Seric CollectErrorMessage = NULL; 8866796Seric CollectErrno = 0; 8967546Seric if (hdrp == NULL) 9067546Seric hdrp = &e->e_header; 9167546Seric else 9267546Seric headeronly = TRUE; 9366796Seric 941392Seric /* 951392Seric ** Create the temp file name and create the file. 961392Seric */ 971392Seric 9867546Seric if (!headeronly) 991392Seric { 100*67617Seric struct stat stbuf; 101*67617Seric 10267546Seric e->e_df = queuename(e, 'd'); 10367546Seric e->e_df = newstr(e->e_df); 10467546Seric if ((tf = dfopen(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL) 10567546Seric { 10667546Seric syserr("Cannot create %s", e->e_df); 10767546Seric e->e_flags |= EF_NORETURN; 10867546Seric finis(); 10967546Seric } 110*67617Seric if (fstat(fileno(tf), &stbuf) < 0) 111*67617Seric e->e_dfino = -1; 112*67617Seric else 113*67617Seric e->e_dfino = stbuf.st_ino; 11467546Seric HasEightBits = FALSE; 1151392Seric } 1161392Seric 1174316Seric /* 1184322Seric ** Tell ARPANET to go ahead. 1194322Seric */ 1204322Seric 12152105Seric if (smtpmode) 12258151Seric message("354 Enter mail, end with \".\" on a line by itself"); 1234322Seric 1244322Seric /* 12567599Seric ** Read the message. 12667599Seric ** 12767599Seric ** This is done using two interleaved state machines. 12867599Seric ** The input state machine is looking for things like 12967599Seric ** hidden dots; the message state machine is handling 13067599Seric ** the larger picture (e.g., header versus body). 1314316Seric */ 1324316Seric 13367599Seric buf = bp = bufbuf; 13467599Seric buflen = sizeof bufbuf; 13567599Seric pbp = peekbuf; 13667599Seric istate = IS_BOL; 13767599Seric mstate = SaveFrom ? MS_HEADER : MS_UFROM; 13867599Seric CollectProgress = FALSE; 13967599Seric 14067599Seric /* if transmitting binary, don't map NL to EOL */ 14167599Seric if (e->e_bodytype != NULL && strcasecmp(e->e_bodytype, "8BITMIME") == 0) 14267599Seric e->e_flags |= EF_NL_NOT_EOL; 14367599Seric 14467599Seric if (dbto != 0) 1452900Seric { 14667599Seric /* handle possible input timeout */ 14767599Seric if (setjmp(CtxCollectTimeout) != 0) 14867599Seric { 14967599Seric #ifdef LOG 15067599Seric syslog(LOG_NOTICE, 15167599Seric "timeout waiting for input from %s during message collect", 15267599Seric CurHostName ? CurHostName : "<local machine>"); 15367599Seric #endif 15467599Seric errno = 0; 15567599Seric usrerr("451 timeout waiting for input during message collect"); 15640965Sbostic goto readerr; 15767599Seric } 15867599Seric CollectTimeout = setevent(dbto, collecttimeout, dbto); 1592900Seric } 1602900Seric 16140965Sbostic for (;;) 1621392Seric { 16367599Seric if (tTd(30, 35)) 16467599Seric printf("top, istate=%d, mstate=%d\n", istate, mstate); 16540965Sbostic for (;;) 1661392Seric { 16767599Seric if (pbp > peekbuf) 16867599Seric c = *--pbp; 16967599Seric else 17064916Seric { 17167599Seric while (!feof(InChannel) && !ferror(InChannel)) 17267599Seric { 17367599Seric errno = 0; 17467599Seric c = fgetc(InChannel); 17567599Seric if (errno != EINTR) 17667599Seric break; 17767599Seric clearerr(InChannel); 17867599Seric } 17967599Seric CollectProgress = TRUE; 18067599Seric if (TrafficLogFile != NULL) 18167599Seric { 18267599Seric if (istate == IS_BOL) 18367599Seric fprintf(TrafficLogFile, "%05d <<< ", 18467599Seric getpid()); 18567599Seric if (c == EOF) 18667599Seric fprintf(TrafficLogFile, "[EOF]\n"); 18767599Seric else 18867599Seric fputc(c, TrafficLogFile); 18967599Seric } 19067599Seric if (c == EOF) 19167599Seric goto readerr; 19267599Seric if (SevenBitInput) 19367599Seric c &= 0x7f; 19467599Seric else 19567599Seric HasEightBits |= bitset(0x80, c); 19667599Seric e->e_msgsize++; 19767599Seric } 19867599Seric if (tTd(30, 94)) 19967599Seric printf("istate=%d, c=%c (0x%x)\n", 20067599Seric istate, c, c); 20167599Seric switch (istate) 20267599Seric { 20367599Seric case IS_BOL: 20467599Seric if (c == '.') 20567599Seric { 20667599Seric istate = IS_DOT; 20767599Seric continue; 20867599Seric } 20964916Seric break; 21040965Sbostic 21167599Seric case IS_DOT: 21267599Seric if (c == '\n' && !ignrdot && 21367599Seric !bitset(EF_NL_NOT_EOL, e->e_flags)) 21467599Seric goto readerr; 21567599Seric else if (c == '\r' && 21667599Seric !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 21767599Seric { 21867599Seric istate = IS_DOTCR; 21967599Seric continue; 22067599Seric } 22167599Seric else if (c != '.' || 22267599Seric (OpMode != MD_SMTP && 22367599Seric OpMode != MD_DAEMON && 22467599Seric OpMode != MD_ARPAFTP)) 22567599Seric { 22667599Seric *pbp++ = c; 22767599Seric c = '.'; 22867599Seric } 2292900Seric break; 23040965Sbostic 23167599Seric case IS_DOTCR: 23267599Seric if (c == '\n') 23367599Seric goto readerr; 23467599Seric else 23567599Seric { 23667599Seric /* push back the ".\rx" */ 23767599Seric *pbp++ = c; 23867599Seric *pbp++ = '\r'; 23967599Seric c = '.'; 24067599Seric } 24167599Seric break; 24240965Sbostic 24367599Seric case IS_CR: 24467599Seric if (c != '\n') 24567599Seric { 24667599Seric ungetc(c, InChannel); 24767599Seric c = '\r'; 24867599Seric } 24967599Seric else if (!bitset(EF_CRLF_NOT_EOL, e->e_flags)) 25067599Seric istate = IS_BOL; 25167599Seric break; 25267599Seric } 25357135Seric 25467599Seric if (c == '\r') 25540965Sbostic { 25667599Seric istate = IS_CR; 25767599Seric continue; 25867599Seric } 25967599Seric else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 26067599Seric istate = IS_BOL; 26167599Seric else 26267599Seric istate = IS_NORM; 26340965Sbostic 26467599Seric if (mstate == MS_BODY) 26567599Seric { 26667599Seric /* just put the character out */ 26767599Seric fputc(c, tf); 26867599Seric continue; 26940965Sbostic } 2701392Seric 27167599Seric /* header -- buffer up */ 27267599Seric if (bp >= &buf[buflen - 2]) 27367599Seric { 27467599Seric char *obuf; 2751392Seric 27667599Seric if (mstate != MS_HEADER) 27767599Seric break; 27840965Sbostic 27967599Seric /* out of space for header */ 28067599Seric obuf = buf; 28167599Seric if (buflen < MEMCHUNKSIZE) 28267599Seric buflen *= 2; 28367599Seric else 28467599Seric buflen += MEMCHUNKSIZE; 28567599Seric buf = xalloc(buflen); 28667599Seric bcopy(obuf, buf, bp - obuf); 28767599Seric bp = &buf[bp - obuf]; 28867599Seric if (obuf != bufbuf) 28967599Seric free(obuf); 29067599Seric } 29167599Seric *bp++ = c; 29267599Seric if (istate == IS_BOL) 29367599Seric break; 29440965Sbostic } 29567599Seric *bp = '\0'; 29640965Sbostic 29767599Seric nextstate: 29867599Seric if (tTd(30, 35)) 29967599Seric printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 30067599Seric istate, mstate, buf); 30167599Seric switch (mstate) 30267599Seric { 30367599Seric case MS_UFROM: 30467599Seric mstate = MS_HEADER; 30567599Seric if (strncmp(buf, "From ", 5) == 0) 30667599Seric { 30767599Seric eatfrom(buf, e); 30867599Seric continue; 30967599Seric } 31067599Seric /* fall through */ 3112900Seric 31267599Seric case MS_HEADER: 31367599Seric if (!isheader(buf)) 31467599Seric { 31567599Seric mstate = MS_BODY; 31667599Seric goto nextstate; 31767599Seric } 31857135Seric 31967599Seric /* check for possible continuation line */ 32067599Seric do 32167599Seric { 32267599Seric clearerr(InChannel); 32367599Seric errno = 0; 32467599Seric c = fgetc(InChannel); 32567599Seric } while (errno == EINTR); 32667599Seric if (c != EOF) 32767599Seric ungetc(c, InChannel); 32867599Seric if (c == ' ' || c == '\t') 32967599Seric { 33067599Seric /* yep -- defer this */ 33167599Seric continue; 33267599Seric } 33357135Seric 33467599Seric /* trim off trailing CRLF or NL */ 33567599Seric if (*--bp != '\n' || *--bp != '\r') 33667599Seric bp++; 33767599Seric *bp = '\0'; 33867599Seric if (bitset(H_EOH, chompheader(buf, FALSE, e))) 33967599Seric mstate = MS_BODY; 34067599Seric break; 3411392Seric 34267599Seric case MS_BODY: 34367599Seric if (tTd(30, 1)) 34467599Seric printf("EOH\n"); 34567599Seric if (headeronly) 34667599Seric goto readerr; 34767599Seric bp = buf; 3482900Seric 34967599Seric /* toss blank line */ 35067599Seric if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 35167599Seric bp[0] == '\r' && bp[1] == '\n') || 35267599Seric (!bitset(EF_NL_NOT_EOL, e->e_flags) && 35367599Seric bp[0] == '\n')) 35467599Seric { 35567599Seric break; 35667599Seric } 35767546Seric 35867599Seric /* if not a blank separator, write it out */ 35967599Seric while (*bp != '\0') 36067599Seric fputc(*bp++, tf); 3612900Seric break; 36267599Seric } 36367599Seric bp = buf; 36464718Seric } 36540965Sbostic 36667546Seric readerr: 36767546Seric if ((feof(fp) && smtpmode) || ferror(fp)) 36864718Seric { 36964916Seric if (tTd(30, 1)) 37064916Seric printf("collect: read error\n"); 37164718Seric inputerr = TRUE; 37264718Seric } 37364718Seric 37466765Seric /* reset global timer */ 37567599Seric clrevent(CollectTimeout); 37666765Seric 37767546Seric if (headeronly) 37867546Seric return; 37967546Seric 38067546Seric if (tf != NULL) 38164762Seric { 38267546Seric if (fflush(tf) != 0) 38367546Seric tferror(tf, e); 38467546Seric if (fsync(fileno(tf)) < 0 || fclose(tf) < 0) 38567546Seric { 38667546Seric tferror(tf, e); 38767546Seric finis(); 38867546Seric } 38964762Seric } 3902900Seric 39166796Seric if (CollectErrorMessage != NULL && Errors <= 0) 39216136Seric { 39366796Seric if (CollectErrno != 0) 39466796Seric { 39566796Seric errno = CollectErrno; 39666796Seric syserr(CollectErrorMessage, e->e_df); 39766796Seric finis(); 39866796Seric } 39966796Seric usrerr(CollectErrorMessage); 40066796Seric } 40166796Seric else if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 40266796Seric { 40366796Seric /* An EOF when running SMTP is an error */ 40458308Seric char *host; 40564718Seric char *problem; 40658082Seric 40758308Seric host = RealHostName; 40858308Seric if (host == NULL) 40958308Seric host = "localhost"; 41058308Seric 41167546Seric if (feof(fp)) 41264718Seric problem = "unexpected close"; 41367546Seric else if (ferror(fp)) 41464718Seric problem = "I/O error"; 41564718Seric else 41664718Seric problem = "read timeout"; 41736233Skarels # ifdef LOG 41867546Seric if (LogLevel > 0 && feof(fp)) 41936230Skarels syslog(LOG_NOTICE, 42066864Seric "collect: %s on connection from %s, sender=%s: %s\n", 42166864Seric problem, host, e->e_from.q_paddr, errstring(errno)); 42236233Skarels # endif 42367546Seric if (feof(fp)) 42465951Seric usrerr("451 collect: %s on connection from %s, from=%s", 42564718Seric problem, host, e->e_from.q_paddr); 42665951Seric else 42765951Seric syserr("451 collect: %s on connection from %s, from=%s", 42865951Seric problem, host, e->e_from.q_paddr); 42911145Seric 43016136Seric /* don't return an error indication */ 43155012Seric e->e_to = NULL; 43255012Seric e->e_flags &= ~EF_FATALERRS; 43364124Seric e->e_flags |= EF_CLRQUEUE; 43416136Seric 43516136Seric /* and don't try to deliver the partial message either */ 43664718Seric if (InChild) 43764718Seric ExitStat = EX_QUIT; 43816136Seric finis(); 43916136Seric } 44016136Seric 4412900Seric /* 4422900Seric ** Find out some information from the headers. 4433386Seric ** Examples are who is the from person & the date. 4442900Seric */ 4452900Seric 44658929Seric eatheader(e, !requeueflag); 4477673Seric 44864068Seric /* collect statistics */ 44964068Seric if (OpMode != MD_VERIFY) 45064068Seric markstats(e, (ADDRESS *) NULL); 45164068Seric 4527782Seric /* 4537782Seric ** Add an Apparently-To: line if we have no recipient lines. 4547782Seric */ 4554622Seric 45667546Seric if (hvalue("to", e->e_header) == NULL && 45767546Seric hvalue("cc", e->e_header) == NULL && 45867546Seric hvalue("bcc", e->e_header) == NULL && 45967546Seric hvalue("apparently-to", e->e_header) == NULL) 4607367Seric { 4617367Seric register ADDRESS *q; 4627367Seric 4637367Seric /* create an Apparently-To: field */ 4647367Seric /* that or reject the message.... */ 46555012Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4667367Seric { 4677389Seric if (q->q_alias != NULL) 4687389Seric continue; 4697673Seric if (tTd(30, 3)) 4707367Seric printf("Adding Apparently-To: %s\n", q->q_paddr); 47167546Seric addheader("Apparently-To", q->q_paddr, &e->e_header); 4727367Seric } 4737367Seric } 4747367Seric 47559320Seric /* check for message too large */ 47659320Seric if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) 47759320Seric { 47859320Seric usrerr("552 Message exceeds maximum fixed size (%ld)", 47959320Seric MaxMessageSize); 48059320Seric } 48159320Seric 48267547Seric /* check for illegal 8-bit data */ 48367547Seric if (HasEightBits) 48467547Seric { 48567547Seric e->e_flags |= EF_HAS8BIT; 48667547Seric if (bitset(MM_MIME8BIT, MimeMode)) 48767547Seric { 48867547Seric /* convert it to MIME */ 48967547Seric if (hvalue("MIME-Version", e->e_header) == NULL) 49067547Seric { 49167547Seric char mimebuf[20]; 49267547Seric 49367547Seric strcpy(mimebuf, "MIME-Version: 1.0"); 49467547Seric chompheader(mimebuf, FALSE, e); 49567547Seric } 49667547Seric if (e->e_bodytype == NULL) 49767547Seric e->e_bodytype = "8BITMIME"; 49867547Seric } 49967547Seric else if (!bitset(MM_PASS8BIT, MimeMode)) 50067547Seric usrerr("554 Eight bit data not allowed"); 50167547Seric } 50267547Seric 50355012Seric if ((e->e_dfp = fopen(e->e_df, "r")) == NULL) 50458690Seric { 50558690Seric /* we haven't acked receipt yet, so just chuck this */ 50655012Seric syserr("Cannot reopen %s", e->e_df); 50758690Seric finis(); 50858690Seric } 5091392Seric } 51040965Sbostic 51167599Seric 51267599Seric static 51367599Seric collecttimeout(timeout) 51467599Seric time_t timeout; 51540965Sbostic { 51667599Seric /* if no progress was made, die now */ 51767599Seric if (!CollectProgress) 51867599Seric longjmp(CtxCollectTimeout, 1); 51940965Sbostic 52067599Seric /* otherwise reset the timeout */ 52167599Seric CollectTimeout = setevent(timeout, collecttimeout, timeout); 52267599Seric CollectProgress = FALSE; 52340965Sbostic } 52440965Sbostic /* 52511544Seric ** TFERROR -- signal error on writing the temporary file. 52611544Seric ** 52711544Seric ** Parameters: 52811544Seric ** tf -- the file pointer for the temporary file. 52911544Seric ** 53011544Seric ** Returns: 53111544Seric ** none. 53211544Seric ** 53311544Seric ** Side Effects: 53411544Seric ** Gives an error message. 53511544Seric ** Arranges for following output to go elsewhere. 53611544Seric */ 53711544Seric 53855012Seric tferror(tf, e) 53911544Seric FILE *tf; 54055012Seric register ENVELOPE *e; 54111544Seric { 54266796Seric CollectErrno = errno; 54311544Seric if (errno == ENOSPC) 54411544Seric { 54566782Seric struct stat st; 54666782Seric long avail; 54766782Seric long bsize; 54866782Seric 54967473Seric e->e_flags |= EF_NORETURN; 55066782Seric if (fstat(fileno(tf), &st) < 0) 55166782Seric st.st_size = 0; 55255012Seric (void) freopen(e->e_df, "w", tf); 55366782Seric if (st.st_size <= 0) 55466782Seric fprintf(tf, "\n*** Mail could not be accepted"); 55566782Seric else if (sizeof st.st_size > sizeof (long)) 55666782Seric fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n", 55766782Seric st.st_size); 55866782Seric else 55966782Seric fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n", 56066782Seric st.st_size); 56166782Seric fprintf(tf, "*** at %s due to lack of disk space for temp file.\n", 56266782Seric MyHostName); 56366782Seric avail = freespace(QueueDir, &bsize); 56466782Seric if (avail > 0) 56566782Seric { 56666782Seric if (bsize > 1024) 56766782Seric avail *= bsize / 1024; 56866782Seric else if (bsize < 1024) 56966782Seric avail /= 1024 / bsize; 57066782Seric fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n", 57166782Seric avail); 57266782Seric } 57366796Seric CollectErrorMessage = "452 Out of disk space for temp file"; 57411544Seric } 57511544Seric else 57666796Seric { 57766796Seric CollectErrorMessage = "cannot write message body to disk (%s)"; 57866796Seric } 57911544Seric (void) freopen("/dev/null", "w", tf); 58011544Seric } 58111544Seric /* 5822900Seric ** EATFROM -- chew up a UNIX style from line and process 5832900Seric ** 5842900Seric ** This does indeed make some assumptions about the format 5852900Seric ** of UNIX messages. 5862900Seric ** 5872900Seric ** Parameters: 5882900Seric ** fm -- the from line. 5892900Seric ** 5902900Seric ** Returns: 5912900Seric ** none. 5922900Seric ** 5932900Seric ** Side Effects: 5942900Seric ** extracts what information it can from the header, 5953386Seric ** such as the date. 5962900Seric */ 5972900Seric 5984321Seric # ifndef NOTUNIX 5994321Seric 6004203Seric char *DowList[] = 6014203Seric { 6024203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 6034203Seric }; 6044203Seric 6052900Seric char *MonthList[] = 6062900Seric { 6072900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 6082900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 6092900Seric NULL 6102900Seric }; 6112900Seric 61255012Seric eatfrom(fm, e) 6132900Seric char *fm; 61455012Seric register ENVELOPE *e; 6152900Seric { 6162900Seric register char *p; 6172900Seric register char **dt; 6182900Seric 6197673Seric if (tTd(30, 2)) 6204203Seric printf("eatfrom(%s)\n", fm); 6214203Seric 6222900Seric /* find the date part */ 6232900Seric p = fm; 6242900Seric while (*p != '\0') 6252900Seric { 6262900Seric /* skip a word */ 6272900Seric while (*p != '\0' && *p != ' ') 62816896Seric p++; 6292900Seric while (*p == ' ') 63016896Seric p++; 63158050Seric if (!(isascii(*p) && isupper(*p)) || 63258050Seric p[3] != ' ' || p[13] != ':' || p[16] != ':') 6332900Seric continue; 6342900Seric 6352900Seric /* we have a possible date */ 6364203Seric for (dt = DowList; *dt != NULL; dt++) 6372900Seric if (strncmp(*dt, p, 3) == 0) 6382900Seric break; 6394203Seric if (*dt == NULL) 6404203Seric continue; 6412900Seric 6424203Seric for (dt = MonthList; *dt != NULL; dt++) 6434203Seric if (strncmp(*dt, &p[4], 3) == 0) 6444203Seric break; 6452900Seric if (*dt != NULL) 6462900Seric break; 6472900Seric } 6482900Seric 64960502Seric if (*p != '\0') 6502900Seric { 6513386Seric char *q; 6525366Seric extern char *arpadate(); 6533386Seric 6542900Seric /* we have found a date */ 6553386Seric q = xalloc(25); 65623103Seric (void) strncpy(q, p, 25); 6573386Seric q[24] = '\0'; 6585366Seric q = arpadate(q); 65955012Seric define('a', newstr(q), e); 6602900Seric } 6612900Seric } 6624321Seric 66356795Seric # endif /* NOTUNIX */ 664