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*69730Seric static char sccsid[] = "@(#)collect.c 8.42 (Berkeley) 05/27/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 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 45664068Seric /* collect statistics */ 45764068Seric if (OpMode != MD_VERIFY) 45868433Seric { 45968433Seric extern void markstats(); 46068433Seric 46164068Seric markstats(e, (ADDRESS *) NULL); 46268433Seric } 46364068Seric 4647782Seric /* 4657782Seric ** Add an Apparently-To: line if we have no recipient lines. 4667782Seric */ 4674622Seric 46867546Seric if (hvalue("to", e->e_header) == NULL && 46967546Seric hvalue("cc", e->e_header) == NULL && 47067546Seric hvalue("bcc", e->e_header) == NULL && 47167546Seric hvalue("apparently-to", e->e_header) == NULL) 4727367Seric { 4737367Seric register ADDRESS *q; 47468449Seric char *hdr = NULL; 47568449Seric extern void addheader(); 4767367Seric 4777367Seric /* create an Apparently-To: field */ 4787367Seric /* that or reject the message.... */ 47968449Seric switch (NoRecipientAction) 4807367Seric { 48168449Seric case NRA_ADD_APPARENTLY_TO: 48268449Seric hdr = "Apparently-To"; 48368449Seric break; 48468433Seric 48568449Seric case NRA_ADD_TO: 48668449Seric hdr = "To"; 48768449Seric break; 48868449Seric 48968449Seric case NRA_ADD_BCC: 49068449Seric addheader("Bcc", "", &e->e_header); 49168449Seric break; 49268449Seric 49368449Seric case NRA_ADD_TO_UNDISCLOSED: 49468449Seric addheader("To", "undisclosed-recipients:;", &e->e_header); 49568449Seric break; 4967367Seric } 49768449Seric 49868449Seric if (hdr != NULL) 49968449Seric { 50068449Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 50168449Seric { 50268449Seric if (q->q_alias != NULL) 50368449Seric continue; 50468449Seric if (tTd(30, 3)) 50568449Seric printf("Adding %s: %s\n", 50668449Seric hdr, q->q_paddr); 50768449Seric addheader(hdr, q->q_paddr, &e->e_header); 50868449Seric } 50968449Seric } 5107367Seric } 5117367Seric 51259320Seric /* check for message too large */ 51359320Seric if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) 51459320Seric { 51568857Seric e->e_status = "5.2.3"; 51659320Seric usrerr("552 Message exceeds maximum fixed size (%ld)", 51759320Seric MaxMessageSize); 518*69730Seric # ifdef LOG 519*69730Seric if (LogLevel > 6) 520*69730Seric syslog(LOG_NOTICE, "%s: message size (%ld) exceeds maximum (%ld)", 521*69730Seric e->e_id, e->e_msgsize, MaxMessageSize); 522*69730Seric # endif 52359320Seric } 52459320Seric 52567547Seric /* check for illegal 8-bit data */ 52667547Seric if (HasEightBits) 52767547Seric { 52867547Seric e->e_flags |= EF_HAS8BIT; 52967887Seric if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode)) 53068857Seric { 53168857Seric e->e_status = "5.6.1"; 53267547Seric usrerr("554 Eight bit data not allowed"); 53368857Seric } 53467547Seric } 53569105Seric else 53669105Seric { 53769105Seric /* if it claimed to be 8 bits, well, it lied.... */ 53869105Seric if (e->e_bodytype != NULL && 53969105Seric strcasecmp(e->e_bodytype, "8BITMIME") == 0) 54069105Seric e->e_bodytype = "7BIT"; 54169105Seric } 54267547Seric 54368564Seric if ((e->e_dfp = fopen(dfname, "r")) == NULL) 54458690Seric { 54558690Seric /* we haven't acked receipt yet, so just chuck this */ 54668564Seric syserr("Cannot reopen %s", dfname); 54758690Seric finis(); 54858690Seric } 5491392Seric } 55040965Sbostic 55167599Seric 55268433Seric static void 55367599Seric collecttimeout(timeout) 55467599Seric time_t timeout; 55540965Sbostic { 55667599Seric /* if no progress was made, die now */ 55767599Seric if (!CollectProgress) 55867599Seric longjmp(CtxCollectTimeout, 1); 55940965Sbostic 56067599Seric /* otherwise reset the timeout */ 56167599Seric CollectTimeout = setevent(timeout, collecttimeout, timeout); 56267599Seric CollectProgress = FALSE; 56340965Sbostic } 56440965Sbostic /* 56511544Seric ** TFERROR -- signal error on writing the temporary file. 56611544Seric ** 56711544Seric ** Parameters: 56811544Seric ** tf -- the file pointer for the temporary file. 56968692Seric ** e -- the current envelope. 57011544Seric ** 57111544Seric ** Returns: 57211544Seric ** none. 57311544Seric ** 57411544Seric ** Side Effects: 57511544Seric ** Gives an error message. 57611544Seric ** Arranges for following output to go elsewhere. 57711544Seric */ 57811544Seric 57968433Seric void 58055012Seric tferror(tf, e) 58111544Seric FILE *tf; 58255012Seric register ENVELOPE *e; 58311544Seric { 58411544Seric if (errno == ENOSPC) 58511544Seric { 58666782Seric struct stat st; 58766782Seric long avail; 58866782Seric long bsize; 58966782Seric 59068559Seric e->e_flags |= EF_NO_BODY_RETN; 59166782Seric if (fstat(fileno(tf), &st) < 0) 59266782Seric st.st_size = 0; 59368564Seric (void) freopen(queuename(e, 'd'), "w", tf); 59466782Seric if (st.st_size <= 0) 59566782Seric fprintf(tf, "\n*** Mail could not be accepted"); 59666782Seric else if (sizeof st.st_size > sizeof (long)) 59766782Seric fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n", 59866782Seric st.st_size); 59966782Seric else 60066782Seric fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n", 60166782Seric st.st_size); 60266782Seric fprintf(tf, "*** at %s due to lack of disk space for temp file.\n", 60366782Seric MyHostName); 60466782Seric avail = freespace(QueueDir, &bsize); 60566782Seric if (avail > 0) 60666782Seric { 60766782Seric if (bsize > 1024) 60866782Seric avail *= bsize / 1024; 60966782Seric else if (bsize < 1024) 61066782Seric avail /= 1024 / bsize; 61166782Seric fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n", 61266782Seric avail); 61366782Seric } 61468857Seric e->e_status = "4.3.1"; 61568692Seric usrerr("452 Out of disk space for temp file"); 61611544Seric } 61711544Seric else 61868692Seric syserr("collect: Cannot write tf%s", e->e_id); 61911544Seric (void) freopen("/dev/null", "w", tf); 62011544Seric } 62111544Seric /* 6222900Seric ** EATFROM -- chew up a UNIX style from line and process 6232900Seric ** 6242900Seric ** This does indeed make some assumptions about the format 6252900Seric ** of UNIX messages. 6262900Seric ** 6272900Seric ** Parameters: 6282900Seric ** fm -- the from line. 6292900Seric ** 6302900Seric ** Returns: 6312900Seric ** none. 6322900Seric ** 6332900Seric ** Side Effects: 6342900Seric ** extracts what information it can from the header, 6353386Seric ** such as the date. 6362900Seric */ 6372900Seric 6384321Seric # ifndef NOTUNIX 6394321Seric 6404203Seric char *DowList[] = 6414203Seric { 6424203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 6434203Seric }; 6444203Seric 6452900Seric char *MonthList[] = 6462900Seric { 6472900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 6482900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 6492900Seric NULL 6502900Seric }; 6512900Seric 65268433Seric void 65355012Seric eatfrom(fm, e) 6542900Seric char *fm; 65555012Seric register ENVELOPE *e; 6562900Seric { 6572900Seric register char *p; 6582900Seric register char **dt; 6592900Seric 6607673Seric if (tTd(30, 2)) 6614203Seric printf("eatfrom(%s)\n", fm); 6624203Seric 6632900Seric /* find the date part */ 6642900Seric p = fm; 6652900Seric while (*p != '\0') 6662900Seric { 6672900Seric /* skip a word */ 6682900Seric while (*p != '\0' && *p != ' ') 66916896Seric p++; 6702900Seric while (*p == ' ') 67116896Seric p++; 67258050Seric if (!(isascii(*p) && isupper(*p)) || 67358050Seric p[3] != ' ' || p[13] != ':' || p[16] != ':') 6742900Seric continue; 6752900Seric 6762900Seric /* we have a possible date */ 6774203Seric for (dt = DowList; *dt != NULL; dt++) 6782900Seric if (strncmp(*dt, p, 3) == 0) 6792900Seric break; 6804203Seric if (*dt == NULL) 6814203Seric continue; 6822900Seric 6834203Seric for (dt = MonthList; *dt != NULL; dt++) 6844203Seric if (strncmp(*dt, &p[4], 3) == 0) 6854203Seric break; 6862900Seric if (*dt != NULL) 6872900Seric break; 6882900Seric } 6892900Seric 69060502Seric if (*p != '\0') 6912900Seric { 6923386Seric char *q; 6935366Seric extern char *arpadate(); 6943386Seric 6952900Seric /* we have found a date */ 6963386Seric q = xalloc(25); 69723103Seric (void) strncpy(q, p, 25); 6983386Seric q[24] = '\0'; 6995366Seric q = arpadate(q); 70055012Seric define('a', newstr(q), e); 7012900Seric } 7022900Seric } 7034321Seric 70456795Seric # endif /* NOTUNIX */ 705