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*68560Seric static char sccsid[] = "@(#)collect.c 8.30 (Berkeley) 03/21/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 4266796Seric char *CollectErrorMessage; 4366796Seric bool CollectErrno; 4466796Seric 4567599Seric static jmp_buf CtxCollectTimeout; 4668433Seric static void 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 6368433Seric void 6467546Seric collect(fp, smtpmode, requeueflag, hdrp, e) 6567546Seric FILE *fp; 6652105Seric bool smtpmode; 6758929Seric bool requeueflag; 6867546Seric HDR **hdrp; 6955012Seric register ENVELOPE *e; 701392Seric { 711392Seric register FILE *tf; 7252105Seric bool ignrdot = smtpmode ? FALSE : IgnrDot; 7367268Seric time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; 7467599Seric register char *bp; 7568433Seric int c = '\0'; 7664718Seric bool inputerr = FALSE; 7767546Seric bool headeronly = FALSE; 7867599Seric char *buf; 7967599Seric int buflen; 8067599Seric int istate; 8167599Seric int mstate; 8267599Seric char *pbp; 8367599Seric char peekbuf[8]; 8467599Seric char bufbuf[MAXLINE]; 8567599Seric extern bool isheader(); 8668433Seric extern void eatheader(); 8768433Seric extern void tferror(); 881392Seric 8966796Seric CollectErrorMessage = NULL; 9066796Seric CollectErrno = 0; 9167546Seric if (hdrp == NULL) 9267546Seric hdrp = &e->e_header; 9367546Seric else 9467546Seric headeronly = TRUE; 9566796Seric 961392Seric /* 971392Seric ** Create the temp file name and create the file. 981392Seric */ 991392Seric 10067546Seric if (!headeronly) 1011392Seric { 10267617Seric struct stat stbuf; 10367617Seric 10467546Seric e->e_df = queuename(e, 'd'); 10567546Seric e->e_df = newstr(e->e_df); 10667546Seric if ((tf = dfopen(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL) 10767546Seric { 10867546Seric syserr("Cannot create %s", e->e_df); 10968559Seric e->e_flags |= EF_NO_BODY_RETN; 11067546Seric finis(); 11167546Seric } 11267617Seric if (fstat(fileno(tf), &stbuf) < 0) 11367617Seric e->e_dfino = -1; 11467617Seric else 11567688Seric { 11667688Seric e->e_dfdev = stbuf.st_dev; 11767617Seric e->e_dfino = stbuf.st_ino; 11867688Seric } 11967546Seric HasEightBits = FALSE; 120*68560Seric e->e_msgsize = 0; 1211392Seric } 1221392Seric 1234316Seric /* 1244322Seric ** Tell ARPANET to go ahead. 1254322Seric */ 1264322Seric 12752105Seric if (smtpmode) 12858151Seric message("354 Enter mail, end with \".\" on a line by itself"); 1294322Seric 1304322Seric /* 13167599Seric ** Read the message. 13267599Seric ** 13367599Seric ** This is done using two interleaved state machines. 13467599Seric ** The input state machine is looking for things like 13567599Seric ** hidden dots; the message state machine is handling 13667599Seric ** the larger picture (e.g., header versus body). 1374316Seric */ 1384316Seric 13967599Seric buf = bp = bufbuf; 14067599Seric buflen = sizeof bufbuf; 14167599Seric pbp = peekbuf; 14267599Seric istate = IS_BOL; 14367599Seric mstate = SaveFrom ? MS_HEADER : MS_UFROM; 14467599Seric CollectProgress = FALSE; 14567599Seric 14667599Seric /* if transmitting binary, don't map NL to EOL */ 14767599Seric if (e->e_bodytype != NULL && strcasecmp(e->e_bodytype, "8BITMIME") == 0) 14867599Seric e->e_flags |= EF_NL_NOT_EOL; 14967599Seric 15067599Seric if (dbto != 0) 1512900Seric { 15267599Seric /* handle possible input timeout */ 15367599Seric if (setjmp(CtxCollectTimeout) != 0) 15467599Seric { 15567599Seric #ifdef LOG 15667599Seric syslog(LOG_NOTICE, 15767599Seric "timeout waiting for input from %s during message collect", 15867599Seric CurHostName ? CurHostName : "<local machine>"); 15967599Seric #endif 16067599Seric errno = 0; 16167599Seric usrerr("451 timeout waiting for input during message collect"); 16240965Sbostic goto readerr; 16367599Seric } 16467599Seric CollectTimeout = setevent(dbto, collecttimeout, dbto); 1652900Seric } 1662900Seric 16740965Sbostic for (;;) 1681392Seric { 16967599Seric if (tTd(30, 35)) 17067599Seric printf("top, istate=%d, mstate=%d\n", istate, mstate); 17140965Sbostic for (;;) 1721392Seric { 17367599Seric if (pbp > peekbuf) 17467599Seric c = *--pbp; 17567599Seric else 17664916Seric { 17767599Seric while (!feof(InChannel) && !ferror(InChannel)) 17867599Seric { 17967599Seric errno = 0; 18067599Seric c = fgetc(InChannel); 18167599Seric if (errno != EINTR) 18267599Seric break; 18367599Seric clearerr(InChannel); 18467599Seric } 18567599Seric CollectProgress = TRUE; 18667599Seric if (TrafficLogFile != NULL) 18767599Seric { 18867599Seric if (istate == IS_BOL) 18967599Seric fprintf(TrafficLogFile, "%05d <<< ", 19067599Seric getpid()); 19167599Seric if (c == EOF) 19267599Seric fprintf(TrafficLogFile, "[EOF]\n"); 19367599Seric else 19467599Seric fputc(c, TrafficLogFile); 19567599Seric } 19667599Seric if (c == EOF) 19767599Seric goto readerr; 19867599Seric if (SevenBitInput) 19967599Seric c &= 0x7f; 20067599Seric else 20167599Seric HasEightBits |= bitset(0x80, c); 202*68560Seric if (!headeronly) 203*68560Seric e->e_msgsize++; 20467599Seric } 20567599Seric if (tTd(30, 94)) 20667599Seric printf("istate=%d, c=%c (0x%x)\n", 20767599Seric istate, c, c); 20867599Seric switch (istate) 20967599Seric { 21067599Seric case IS_BOL: 21167599Seric if (c == '.') 21267599Seric { 21367599Seric istate = IS_DOT; 21467599Seric continue; 21567599Seric } 21664916Seric break; 21740965Sbostic 21867599Seric case IS_DOT: 21967599Seric if (c == '\n' && !ignrdot && 22067599Seric !bitset(EF_NL_NOT_EOL, e->e_flags)) 22167599Seric goto readerr; 22267599Seric else if (c == '\r' && 22367599Seric !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 22467599Seric { 22567599Seric istate = IS_DOTCR; 22667599Seric continue; 22767599Seric } 22867599Seric else if (c != '.' || 22967599Seric (OpMode != MD_SMTP && 23067599Seric OpMode != MD_DAEMON && 23167599Seric OpMode != MD_ARPAFTP)) 23267599Seric { 23367599Seric *pbp++ = c; 23467599Seric c = '.'; 23567599Seric } 2362900Seric break; 23740965Sbostic 23867599Seric case IS_DOTCR: 23967599Seric if (c == '\n') 24067599Seric goto readerr; 24167599Seric else 24267599Seric { 24367599Seric /* push back the ".\rx" */ 24467599Seric *pbp++ = c; 24567599Seric *pbp++ = '\r'; 24667599Seric c = '.'; 24767599Seric } 24867599Seric break; 24940965Sbostic 25067599Seric case IS_CR: 25167689Seric if (c == '\n') 25267689Seric istate = IS_BOL; 25367689Seric else 25467599Seric { 25567599Seric ungetc(c, InChannel); 25667599Seric c = '\r'; 25767689Seric istate = IS_NORM; 25867599Seric } 25967689Seric goto bufferchar; 26067599Seric } 26157135Seric 26267689Seric if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 26340965Sbostic { 26467599Seric istate = IS_CR; 26567599Seric continue; 26667599Seric } 26767599Seric else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 26867599Seric istate = IS_BOL; 26967599Seric else 27067599Seric istate = IS_NORM; 27140965Sbostic 27267689Seric bufferchar: 27367599Seric if (mstate == MS_BODY) 27467599Seric { 27567599Seric /* just put the character out */ 27667831Seric if (MaxMessageSize <= 0 || 27767831Seric e->e_msgsize <= MaxMessageSize) 27867831Seric fputc(c, tf); 27967599Seric continue; 28040965Sbostic } 2811392Seric 28267599Seric /* header -- buffer up */ 28367599Seric if (bp >= &buf[buflen - 2]) 28467599Seric { 28567599Seric char *obuf; 2861392Seric 28767599Seric if (mstate != MS_HEADER) 28867599Seric break; 28940965Sbostic 29067599Seric /* out of space for header */ 29167599Seric obuf = buf; 29267599Seric if (buflen < MEMCHUNKSIZE) 29367599Seric buflen *= 2; 29467599Seric else 29567599Seric buflen += MEMCHUNKSIZE; 29667599Seric buf = xalloc(buflen); 29767599Seric bcopy(obuf, buf, bp - obuf); 29867599Seric bp = &buf[bp - obuf]; 29967599Seric if (obuf != bufbuf) 30067599Seric free(obuf); 30167599Seric } 30267599Seric *bp++ = c; 30367599Seric if (istate == IS_BOL) 30467599Seric break; 30540965Sbostic } 30667599Seric *bp = '\0'; 30740965Sbostic 30867599Seric nextstate: 30967599Seric if (tTd(30, 35)) 31067599Seric printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 31167599Seric istate, mstate, buf); 31267599Seric switch (mstate) 31367599Seric { 31468433Seric extern int chompheader(); 31568433Seric 31667599Seric case MS_UFROM: 31767599Seric mstate = MS_HEADER; 31867599Seric if (strncmp(buf, "From ", 5) == 0) 31967599Seric { 32068433Seric extern void eatfrom(); 32168433Seric 32267704Seric bp = buf; 32367599Seric eatfrom(buf, e); 32467599Seric continue; 32567599Seric } 32667599Seric /* fall through */ 3272900Seric 32867599Seric case MS_HEADER: 32967599Seric if (!isheader(buf)) 33067599Seric { 33167599Seric mstate = MS_BODY; 33267599Seric goto nextstate; 33367599Seric } 33457135Seric 33567599Seric /* check for possible continuation line */ 33667599Seric do 33767599Seric { 33867599Seric clearerr(InChannel); 33967599Seric errno = 0; 34067599Seric c = fgetc(InChannel); 34167599Seric } while (errno == EINTR); 34267599Seric if (c != EOF) 34367599Seric ungetc(c, InChannel); 34467599Seric if (c == ' ' || c == '\t') 34567599Seric { 34667599Seric /* yep -- defer this */ 34767599Seric continue; 34867599Seric } 34957135Seric 35067599Seric /* trim off trailing CRLF or NL */ 35167599Seric if (*--bp != '\n' || *--bp != '\r') 35267599Seric bp++; 35367599Seric *bp = '\0'; 35467599Seric if (bitset(H_EOH, chompheader(buf, FALSE, e))) 35567599Seric mstate = MS_BODY; 35667599Seric break; 3571392Seric 35867599Seric case MS_BODY: 35967599Seric if (tTd(30, 1)) 36067599Seric printf("EOH\n"); 36167599Seric if (headeronly) 36267599Seric goto readerr; 36367599Seric bp = buf; 3642900Seric 36567599Seric /* toss blank line */ 36667599Seric if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 36767599Seric bp[0] == '\r' && bp[1] == '\n') || 36867599Seric (!bitset(EF_NL_NOT_EOL, e->e_flags) && 36967599Seric bp[0] == '\n')) 37067599Seric { 37167599Seric break; 37267599Seric } 37367546Seric 37467599Seric /* if not a blank separator, write it out */ 37567831Seric if (MaxMessageSize <= 0 || 37667831Seric e->e_msgsize <= MaxMessageSize) 37767831Seric { 37867831Seric while (*bp != '\0') 37967831Seric fputc(*bp++, tf); 38067831Seric } 3812900Seric break; 38267599Seric } 38367599Seric bp = buf; 38464718Seric } 38540965Sbostic 38667546Seric readerr: 38767546Seric if ((feof(fp) && smtpmode) || ferror(fp)) 38864718Seric { 38964916Seric if (tTd(30, 1)) 39064916Seric printf("collect: read error\n"); 39164718Seric inputerr = TRUE; 39264718Seric } 39364718Seric 39466765Seric /* reset global timer */ 39567599Seric clrevent(CollectTimeout); 39666765Seric 39767546Seric if (headeronly) 39867546Seric return; 39967546Seric 40067546Seric if (tf != NULL) 40164762Seric { 40267546Seric if (fflush(tf) != 0) 40367546Seric tferror(tf, e); 40467546Seric if (fsync(fileno(tf)) < 0 || fclose(tf) < 0) 40567546Seric { 40667546Seric tferror(tf, e); 40767546Seric finis(); 40867546Seric } 40964762Seric } 4102900Seric 41166796Seric if (CollectErrorMessage != NULL && Errors <= 0) 41216136Seric { 41366796Seric if (CollectErrno != 0) 41466796Seric { 41566796Seric errno = CollectErrno; 41666796Seric syserr(CollectErrorMessage, e->e_df); 41766796Seric finis(); 41866796Seric } 41966796Seric usrerr(CollectErrorMessage); 42066796Seric } 42166796Seric else if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 42266796Seric { 42366796Seric /* An EOF when running SMTP is an error */ 42458308Seric char *host; 42564718Seric char *problem; 42658082Seric 42758308Seric host = RealHostName; 42858308Seric if (host == NULL) 42958308Seric host = "localhost"; 43058308Seric 43167546Seric if (feof(fp)) 43264718Seric problem = "unexpected close"; 43367546Seric else if (ferror(fp)) 43464718Seric problem = "I/O error"; 43564718Seric else 43664718Seric problem = "read timeout"; 43736233Skarels # ifdef LOG 43867546Seric if (LogLevel > 0 && feof(fp)) 43936230Skarels syslog(LOG_NOTICE, 44066864Seric "collect: %s on connection from %s, sender=%s: %s\n", 44166864Seric problem, host, e->e_from.q_paddr, errstring(errno)); 44236233Skarels # endif 44367546Seric if (feof(fp)) 44465951Seric usrerr("451 collect: %s on connection from %s, from=%s", 44564718Seric problem, host, e->e_from.q_paddr); 44665951Seric else 44765951Seric syserr("451 collect: %s on connection from %s, from=%s", 44865951Seric problem, host, e->e_from.q_paddr); 44911145Seric 45016136Seric /* don't return an error indication */ 45155012Seric e->e_to = NULL; 45255012Seric e->e_flags &= ~EF_FATALERRS; 45364124Seric e->e_flags |= EF_CLRQUEUE; 45416136Seric 45516136Seric /* and don't try to deliver the partial message either */ 45664718Seric if (InChild) 45764718Seric ExitStat = EX_QUIT; 45816136Seric finis(); 45916136Seric } 46016136Seric 4612900Seric /* 4622900Seric ** Find out some information from the headers. 4633386Seric ** Examples are who is the from person & the date. 4642900Seric */ 4652900Seric 46658929Seric eatheader(e, !requeueflag); 4677673Seric 46864068Seric /* collect statistics */ 46964068Seric if (OpMode != MD_VERIFY) 47068433Seric { 47168433Seric extern void markstats(); 47268433Seric 47364068Seric markstats(e, (ADDRESS *) NULL); 47468433Seric } 47564068Seric 4767782Seric /* 4777782Seric ** Add an Apparently-To: line if we have no recipient lines. 4787782Seric */ 4794622Seric 48067546Seric if (hvalue("to", e->e_header) == NULL && 48167546Seric hvalue("cc", e->e_header) == NULL && 48267546Seric hvalue("bcc", e->e_header) == NULL && 48367546Seric hvalue("apparently-to", e->e_header) == NULL) 4847367Seric { 4857367Seric register ADDRESS *q; 48668449Seric char *hdr = NULL; 48768449Seric extern void addheader(); 4887367Seric 4897367Seric /* create an Apparently-To: field */ 4907367Seric /* that or reject the message.... */ 49168449Seric switch (NoRecipientAction) 4927367Seric { 49368449Seric case NRA_ADD_APPARENTLY_TO: 49468449Seric hdr = "Apparently-To"; 49568449Seric break; 49668433Seric 49768449Seric case NRA_ADD_TO: 49868449Seric hdr = "To"; 49968449Seric break; 50068449Seric 50168449Seric case NRA_ADD_BCC: 50268449Seric addheader("Bcc", "", &e->e_header); 50368449Seric break; 50468449Seric 50568449Seric case NRA_ADD_TO_UNDISCLOSED: 50668449Seric addheader("To", "undisclosed-recipients:;", &e->e_header); 50768449Seric break; 5087367Seric } 50968449Seric 51068449Seric if (hdr != NULL) 51168449Seric { 51268449Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 51368449Seric { 51468449Seric if (q->q_alias != NULL) 51568449Seric continue; 51668449Seric if (tTd(30, 3)) 51768449Seric printf("Adding %s: %s\n", 51868449Seric hdr, q->q_paddr); 51968449Seric addheader(hdr, q->q_paddr, &e->e_header); 52068449Seric } 52168449Seric } 5227367Seric } 5237367Seric 52459320Seric /* check for message too large */ 52559320Seric if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) 52659320Seric { 52759320Seric usrerr("552 Message exceeds maximum fixed size (%ld)", 52859320Seric MaxMessageSize); 52959320Seric } 53059320Seric 53167547Seric /* check for illegal 8-bit data */ 53267547Seric if (HasEightBits) 53367547Seric { 53467547Seric e->e_flags |= EF_HAS8BIT; 53567887Seric if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode)) 53667547Seric usrerr("554 Eight bit data not allowed"); 53767547Seric } 53867547Seric 53955012Seric if ((e->e_dfp = fopen(e->e_df, "r")) == NULL) 54058690Seric { 54158690Seric /* we haven't acked receipt yet, so just chuck this */ 54255012Seric syserr("Cannot reopen %s", e->e_df); 54358690Seric finis(); 54458690Seric } 5451392Seric } 54640965Sbostic 54767599Seric 54868433Seric static void 54967599Seric collecttimeout(timeout) 55067599Seric time_t timeout; 55140965Sbostic { 55267599Seric /* if no progress was made, die now */ 55367599Seric if (!CollectProgress) 55467599Seric longjmp(CtxCollectTimeout, 1); 55540965Sbostic 55667599Seric /* otherwise reset the timeout */ 55767599Seric CollectTimeout = setevent(timeout, collecttimeout, timeout); 55867599Seric CollectProgress = FALSE; 55940965Sbostic } 56040965Sbostic /* 56111544Seric ** TFERROR -- signal error on writing the temporary file. 56211544Seric ** 56311544Seric ** Parameters: 56411544Seric ** tf -- the file pointer for the temporary file. 56511544Seric ** 56611544Seric ** Returns: 56711544Seric ** none. 56811544Seric ** 56911544Seric ** Side Effects: 57011544Seric ** Gives an error message. 57111544Seric ** Arranges for following output to go elsewhere. 57211544Seric */ 57311544Seric 57468433Seric void 57555012Seric tferror(tf, e) 57611544Seric FILE *tf; 57755012Seric register ENVELOPE *e; 57811544Seric { 57966796Seric CollectErrno = errno; 58011544Seric if (errno == ENOSPC) 58111544Seric { 58266782Seric struct stat st; 58366782Seric long avail; 58466782Seric long bsize; 58566782Seric 58668559Seric e->e_flags |= EF_NO_BODY_RETN; 58766782Seric if (fstat(fileno(tf), &st) < 0) 58866782Seric st.st_size = 0; 58955012Seric (void) freopen(e->e_df, "w", tf); 59066782Seric if (st.st_size <= 0) 59166782Seric fprintf(tf, "\n*** Mail could not be accepted"); 59266782Seric else if (sizeof st.st_size > sizeof (long)) 59366782Seric fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n", 59466782Seric st.st_size); 59566782Seric else 59666782Seric fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n", 59766782Seric st.st_size); 59866782Seric fprintf(tf, "*** at %s due to lack of disk space for temp file.\n", 59966782Seric MyHostName); 60066782Seric avail = freespace(QueueDir, &bsize); 60166782Seric if (avail > 0) 60266782Seric { 60366782Seric if (bsize > 1024) 60466782Seric avail *= bsize / 1024; 60566782Seric else if (bsize < 1024) 60666782Seric avail /= 1024 / bsize; 60766782Seric fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n", 60866782Seric avail); 60966782Seric } 61066796Seric CollectErrorMessage = "452 Out of disk space for temp file"; 61111544Seric } 61211544Seric else 61366796Seric { 61466796Seric CollectErrorMessage = "cannot write message body to disk (%s)"; 61566796Seric } 61611544Seric (void) freopen("/dev/null", "w", tf); 61711544Seric } 61811544Seric /* 6192900Seric ** EATFROM -- chew up a UNIX style from line and process 6202900Seric ** 6212900Seric ** This does indeed make some assumptions about the format 6222900Seric ** of UNIX messages. 6232900Seric ** 6242900Seric ** Parameters: 6252900Seric ** fm -- the from line. 6262900Seric ** 6272900Seric ** Returns: 6282900Seric ** none. 6292900Seric ** 6302900Seric ** Side Effects: 6312900Seric ** extracts what information it can from the header, 6323386Seric ** such as the date. 6332900Seric */ 6342900Seric 6354321Seric # ifndef NOTUNIX 6364321Seric 6374203Seric char *DowList[] = 6384203Seric { 6394203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 6404203Seric }; 6414203Seric 6422900Seric char *MonthList[] = 6432900Seric { 6442900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 6452900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 6462900Seric NULL 6472900Seric }; 6482900Seric 64968433Seric void 65055012Seric eatfrom(fm, e) 6512900Seric char *fm; 65255012Seric register ENVELOPE *e; 6532900Seric { 6542900Seric register char *p; 6552900Seric register char **dt; 6562900Seric 6577673Seric if (tTd(30, 2)) 6584203Seric printf("eatfrom(%s)\n", fm); 6594203Seric 6602900Seric /* find the date part */ 6612900Seric p = fm; 6622900Seric while (*p != '\0') 6632900Seric { 6642900Seric /* skip a word */ 6652900Seric while (*p != '\0' && *p != ' ') 66616896Seric p++; 6672900Seric while (*p == ' ') 66816896Seric p++; 66958050Seric if (!(isascii(*p) && isupper(*p)) || 67058050Seric p[3] != ' ' || p[13] != ':' || p[16] != ':') 6712900Seric continue; 6722900Seric 6732900Seric /* we have a possible date */ 6744203Seric for (dt = DowList; *dt != NULL; dt++) 6752900Seric if (strncmp(*dt, p, 3) == 0) 6762900Seric break; 6774203Seric if (*dt == NULL) 6784203Seric continue; 6792900Seric 6804203Seric for (dt = MonthList; *dt != NULL; dt++) 6814203Seric if (strncmp(*dt, &p[4], 3) == 0) 6824203Seric break; 6832900Seric if (*dt != NULL) 6842900Seric break; 6852900Seric } 6862900Seric 68760502Seric if (*p != '\0') 6882900Seric { 6893386Seric char *q; 6905366Seric extern char *arpadate(); 6913386Seric 6922900Seric /* we have found a date */ 6933386Seric q = xalloc(25); 69423103Seric (void) strncpy(q, p, 25); 6953386Seric q[24] = '\0'; 6965366Seric q = arpadate(q); 69755012Seric define('a', newstr(q), e); 6982900Seric } 6992900Seric } 7004321Seric 70156795Seric # endif /* NOTUNIX */ 702