collect.c revision 38032
138032Speter/* 238032Speter * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 438032Speter * Copyright (c) 1988, 1993 538032Speter * The Regents of the University of California. All rights reserved. 638032Speter * 738032Speter * By using this file, you agree to the terms and conditions set 838032Speter * forth in the LICENSE file which can be found at the top level of 938032Speter * the sendmail distribution. 1038032Speter * 1138032Speter */ 1238032Speter 1338032Speter#ifndef lint 1438032Speterstatic char sccsid[] = "@(#)collect.c 8.89 (Berkeley) 6/4/98"; 1538032Speter#endif /* not lint */ 1638032Speter 1738032Speter# include <errno.h> 1838032Speter# include "sendmail.h" 1938032Speter 2038032Speter/* 2138032Speter** COLLECT -- read & parse message header & make temp file. 2238032Speter** 2338032Speter** Creates a temporary file name and copies the standard 2438032Speter** input to that file. Leading UNIX-style "From" lines are 2538032Speter** stripped off (after important information is extracted). 2638032Speter** 2738032Speter** Parameters: 2838032Speter** fp -- file to read. 2938032Speter** smtpmode -- if set, we are running SMTP: give an RFC821 3038032Speter** style message to say we are ready to collect 3138032Speter** input, and never ignore a single dot to mean 3238032Speter** end of message. 3338032Speter** hdrp -- the location to stash the header. 3438032Speter** e -- the current envelope. 3538032Speter** 3638032Speter** Returns: 3738032Speter** none. 3838032Speter** 3938032Speter** Side Effects: 4038032Speter** Temp file is created and filled. 4138032Speter** The from person may be set. 4238032Speter*/ 4338032Speter 4438032Speterstatic jmp_buf CtxCollectTimeout; 4538032Speterstatic void collecttimeout __P((time_t)); 4638032Speterstatic bool CollectProgress; 4738032Speterstatic EVENT *CollectTimeout; 4838032Speter 4938032Speter/* values for input state machine */ 5038032Speter#define IS_NORM 0 /* middle of line */ 5138032Speter#define IS_BOL 1 /* beginning of line */ 5238032Speter#define IS_DOT 2 /* read a dot at beginning of line */ 5338032Speter#define IS_DOTCR 3 /* read ".\r" at beginning of line */ 5438032Speter#define IS_CR 4 /* read a carriage return */ 5538032Speter 5638032Speter/* values for message state machine */ 5738032Speter#define MS_UFROM 0 /* reading Unix from line */ 5838032Speter#define MS_HEADER 1 /* reading message header */ 5938032Speter#define MS_BODY 2 /* reading message body */ 6038032Speter 6138032Spetervoid 6238032Spetercollect(fp, smtpmode, hdrp, e) 6338032Speter FILE *fp; 6438032Speter bool smtpmode; 6538032Speter HDR **hdrp; 6638032Speter register ENVELOPE *e; 6738032Speter{ 6838032Speter register FILE *volatile tf; 6938032Speter volatile bool ignrdot = smtpmode ? FALSE : IgnrDot; 7038032Speter volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; 7138032Speter register char *volatile bp; 7238032Speter volatile int c = EOF; 7338032Speter volatile bool inputerr = FALSE; 7438032Speter bool headeronly; 7538032Speter char *volatile buf; 7638032Speter volatile int buflen; 7738032Speter volatile int istate; 7838032Speter volatile int mstate; 7938032Speter u_char *volatile pbp; 8038032Speter u_char peekbuf[8]; 8138032Speter char dfname[MAXQFNAME]; 8238032Speter char bufbuf[MAXLINE]; 8338032Speter extern bool isheader __P((char *)); 8438032Speter extern void eatheader __P((ENVELOPE *, bool)); 8538032Speter extern void tferror __P((FILE *volatile, ENVELOPE *)); 8638032Speter 8738032Speter headeronly = hdrp != NULL; 8838032Speter 8938032Speter /* 9038032Speter ** Create the temp file name and create the file. 9138032Speter */ 9238032Speter 9338032Speter if (!headeronly) 9438032Speter { 9538032Speter int tfd; 9638032Speter struct stat stbuf; 9738032Speter 9838032Speter strcpy(dfname, queuename(e, 'd')); 9938032Speter tfd = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode, SFF_ANYFILE); 10038032Speter if (tfd < 0 || (tf = fdopen(tfd, "w")) == NULL) 10138032Speter { 10238032Speter syserr("Cannot create %s", dfname); 10338032Speter e->e_flags |= EF_NO_BODY_RETN; 10438032Speter finis(); 10538032Speter } 10638032Speter if (fstat(fileno(tf), &stbuf) < 0) 10738032Speter e->e_dfino = -1; 10838032Speter else 10938032Speter { 11038032Speter e->e_dfdev = stbuf.st_dev; 11138032Speter e->e_dfino = stbuf.st_ino; 11238032Speter } 11338032Speter HasEightBits = FALSE; 11438032Speter e->e_msgsize = 0; 11538032Speter e->e_flags |= EF_HAS_DF; 11638032Speter } 11738032Speter 11838032Speter /* 11938032Speter ** Tell ARPANET to go ahead. 12038032Speter */ 12138032Speter 12238032Speter if (smtpmode) 12338032Speter message("354 Enter mail, end with \".\" on a line by itself"); 12438032Speter 12538032Speter if (tTd(30, 2)) 12638032Speter printf("collect\n"); 12738032Speter 12838032Speter /* 12938032Speter ** Read the message. 13038032Speter ** 13138032Speter ** This is done using two interleaved state machines. 13238032Speter ** The input state machine is looking for things like 13338032Speter ** hidden dots; the message state machine is handling 13438032Speter ** the larger picture (e.g., header versus body). 13538032Speter */ 13638032Speter 13738032Speter buf = bp = bufbuf; 13838032Speter buflen = sizeof bufbuf; 13938032Speter pbp = peekbuf; 14038032Speter istate = IS_BOL; 14138032Speter mstate = SaveFrom ? MS_HEADER : MS_UFROM; 14238032Speter CollectProgress = FALSE; 14338032Speter 14438032Speter if (dbto != 0) 14538032Speter { 14638032Speter /* handle possible input timeout */ 14738032Speter if (setjmp(CtxCollectTimeout) != 0) 14838032Speter { 14938032Speter if (LogLevel > 2) 15038032Speter sm_syslog(LOG_NOTICE, e->e_id, 15138032Speter "timeout waiting for input from %s during message collect", 15238032Speter CurHostName ? CurHostName : "<local machine>"); 15338032Speter errno = 0; 15438032Speter usrerr("451 timeout waiting for input during message collect"); 15538032Speter goto readerr; 15638032Speter } 15738032Speter CollectTimeout = setevent(dbto, collecttimeout, dbto); 15838032Speter } 15938032Speter 16038032Speter for (;;) 16138032Speter { 16238032Speter extern int chompheader __P((char *, bool, HDR **, ENVELOPE *)); 16338032Speter 16438032Speter if (tTd(30, 35)) 16538032Speter printf("top, istate=%d, mstate=%d\n", istate, mstate); 16638032Speter for (;;) 16738032Speter { 16838032Speter if (pbp > peekbuf) 16938032Speter c = *--pbp; 17038032Speter else 17138032Speter { 17238032Speter while (!feof(fp) && !ferror(fp)) 17338032Speter { 17438032Speter errno = 0; 17538032Speter c = getc(fp); 17638032Speter if (errno != EINTR) 17738032Speter break; 17838032Speter clearerr(fp); 17938032Speter } 18038032Speter CollectProgress = TRUE; 18138032Speter if (TrafficLogFile != NULL && !headeronly) 18238032Speter { 18338032Speter if (istate == IS_BOL) 18438032Speter fprintf(TrafficLogFile, "%05d <<< ", 18538032Speter (int) getpid()); 18638032Speter if (c == EOF) 18738032Speter fprintf(TrafficLogFile, "[EOF]\n"); 18838032Speter else 18938032Speter putc(c, TrafficLogFile); 19038032Speter } 19138032Speter if (c == EOF) 19238032Speter goto readerr; 19338032Speter if (SevenBitInput) 19438032Speter c &= 0x7f; 19538032Speter else 19638032Speter HasEightBits |= bitset(0x80, c); 19738032Speter } 19838032Speter if (tTd(30, 94)) 19938032Speter printf("istate=%d, c=%c (0x%x)\n", 20038032Speter istate, c, c); 20138032Speter switch (istate) 20238032Speter { 20338032Speter case IS_BOL: 20438032Speter if (c == '.') 20538032Speter { 20638032Speter istate = IS_DOT; 20738032Speter continue; 20838032Speter } 20938032Speter break; 21038032Speter 21138032Speter case IS_DOT: 21238032Speter if (c == '\n' && !ignrdot && 21338032Speter !bitset(EF_NL_NOT_EOL, e->e_flags)) 21438032Speter goto readerr; 21538032Speter else if (c == '\r' && 21638032Speter !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 21738032Speter { 21838032Speter istate = IS_DOTCR; 21938032Speter continue; 22038032Speter } 22138032Speter else if (c != '.' || 22238032Speter (OpMode != MD_SMTP && 22338032Speter OpMode != MD_DAEMON && 22438032Speter OpMode != MD_ARPAFTP)) 22538032Speter { 22638032Speter *pbp++ = c; 22738032Speter c = '.'; 22838032Speter } 22938032Speter break; 23038032Speter 23138032Speter case IS_DOTCR: 23238032Speter if (c == '\n' && !ignrdot) 23338032Speter goto readerr; 23438032Speter else 23538032Speter { 23638032Speter /* push back the ".\rx" */ 23738032Speter *pbp++ = c; 23838032Speter *pbp++ = '\r'; 23938032Speter c = '.'; 24038032Speter } 24138032Speter break; 24238032Speter 24338032Speter case IS_CR: 24438032Speter if (c == '\n') 24538032Speter istate = IS_BOL; 24638032Speter else 24738032Speter { 24838032Speter ungetc(c, fp); 24938032Speter c = '\r'; 25038032Speter istate = IS_NORM; 25138032Speter } 25238032Speter goto bufferchar; 25338032Speter } 25438032Speter 25538032Speter if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 25638032Speter { 25738032Speter istate = IS_CR; 25838032Speter continue; 25938032Speter } 26038032Speter else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 26138032Speter istate = IS_BOL; 26238032Speter else 26338032Speter istate = IS_NORM; 26438032Speter 26538032Speterbufferchar: 26638032Speter if (!headeronly) 26738032Speter e->e_msgsize++; 26838032Speter if (mstate == MS_BODY) 26938032Speter { 27038032Speter /* just put the character out */ 27138032Speter if (MaxMessageSize <= 0 || 27238032Speter e->e_msgsize <= MaxMessageSize) 27338032Speter putc(c, tf); 27438032Speter continue; 27538032Speter } 27638032Speter 27738032Speter /* header -- buffer up */ 27838032Speter if (bp >= &buf[buflen - 2]) 27938032Speter { 28038032Speter char *obuf; 28138032Speter 28238032Speter if (mstate != MS_HEADER) 28338032Speter break; 28438032Speter 28538032Speter /* out of space for header */ 28638032Speter obuf = buf; 28738032Speter if (buflen < MEMCHUNKSIZE) 28838032Speter buflen *= 2; 28938032Speter else 29038032Speter buflen += MEMCHUNKSIZE; 29138032Speter buf = xalloc(buflen); 29238032Speter bcopy(obuf, buf, bp - obuf); 29338032Speter bp = &buf[bp - obuf]; 29438032Speter if (obuf != bufbuf) 29538032Speter free(obuf); 29638032Speter } 29738032Speter if (c >= 0200 && c <= 0237) 29838032Speter { 29938032Speter#if 0 /* causes complaints -- figure out something for 8.9 */ 30038032Speter usrerr("Illegal character 0x%x in header", c); 30138032Speter#endif 30238032Speter } 30338032Speter else if (c != '\0') 30438032Speter *bp++ = c; 30538032Speter if (istate == IS_BOL) 30638032Speter break; 30738032Speter } 30838032Speter *bp = '\0'; 30938032Speter 31038032Speternextstate: 31138032Speter if (tTd(30, 35)) 31238032Speter printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 31338032Speter istate, mstate, buf); 31438032Speter switch (mstate) 31538032Speter { 31638032Speter case MS_UFROM: 31738032Speter mstate = MS_HEADER; 31838032Speter#ifndef NOTUNIX 31938032Speter if (strncmp(buf, "From ", 5) == 0) 32038032Speter { 32138032Speter extern void eatfrom __P((char *volatile, ENVELOPE *)); 32238032Speter 32338032Speter bp = buf; 32438032Speter eatfrom(buf, e); 32538032Speter continue; 32638032Speter } 32738032Speter#endif 32838032Speter /* fall through */ 32938032Speter 33038032Speter case MS_HEADER: 33138032Speter if (!isheader(buf)) 33238032Speter { 33338032Speter mstate = MS_BODY; 33438032Speter goto nextstate; 33538032Speter } 33638032Speter 33738032Speter /* check for possible continuation line */ 33838032Speter do 33938032Speter { 34038032Speter clearerr(fp); 34138032Speter errno = 0; 34238032Speter c = getc(fp); 34338032Speter } while (errno == EINTR); 34438032Speter if (c != EOF) 34538032Speter ungetc(c, fp); 34638032Speter if (c == ' ' || c == '\t') 34738032Speter { 34838032Speter /* yep -- defer this */ 34938032Speter continue; 35038032Speter } 35138032Speter 35238032Speter /* trim off trailing CRLF or NL */ 35338032Speter if (*--bp != '\n' || *--bp != '\r') 35438032Speter bp++; 35538032Speter *bp = '\0'; 35638032Speter if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e))) 35738032Speter { 35838032Speter mstate = MS_BODY; 35938032Speter goto nextstate; 36038032Speter } 36138032Speter break; 36238032Speter 36338032Speter case MS_BODY: 36438032Speter if (tTd(30, 1)) 36538032Speter printf("EOH\n"); 36638032Speter if (headeronly) 36738032Speter goto readerr; 36838032Speter bp = buf; 36938032Speter 37038032Speter /* toss blank line */ 37138032Speter if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 37238032Speter bp[0] == '\r' && bp[1] == '\n') || 37338032Speter (!bitset(EF_NL_NOT_EOL, e->e_flags) && 37438032Speter bp[0] == '\n')) 37538032Speter { 37638032Speter break; 37738032Speter } 37838032Speter 37938032Speter /* if not a blank separator, write it out */ 38038032Speter if (MaxMessageSize <= 0 || 38138032Speter e->e_msgsize <= MaxMessageSize) 38238032Speter { 38338032Speter while (*bp != '\0') 38438032Speter putc(*bp++, tf); 38538032Speter } 38638032Speter break; 38738032Speter } 38838032Speter bp = buf; 38938032Speter } 39038032Speter 39138032Speterreaderr: 39238032Speter if ((feof(fp) && smtpmode) || ferror(fp)) 39338032Speter { 39438032Speter const char *errmsg = errstring(errno); 39538032Speter 39638032Speter if (tTd(30, 1)) 39738032Speter printf("collect: premature EOM: %s\n", errmsg); 39838032Speter if (LogLevel >= 2) 39938032Speter sm_syslog(LOG_WARNING, e->e_id, 40038032Speter "collect: premature EOM: %s", errmsg); 40138032Speter inputerr = TRUE; 40238032Speter } 40338032Speter 40438032Speter /* reset global timer */ 40538032Speter clrevent(CollectTimeout); 40638032Speter 40738032Speter if (headeronly) 40838032Speter return; 40938032Speter 41038032Speter if (tf != NULL && 41138032Speter (fflush(tf) != 0 || ferror(tf) || 41238032Speter (SuperSafe && fsync(fileno(tf)) < 0) || 41338032Speter fclose(tf) < 0)) 41438032Speter { 41538032Speter tferror(tf, e); 41638032Speter flush_errors(TRUE); 41738032Speter finis(); 41838032Speter } 41938032Speter 42038032Speter /* An EOF when running SMTP is an error */ 42138032Speter if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 42238032Speter { 42338032Speter char *host; 42438032Speter char *problem; 42538032Speter 42638032Speter host = RealHostName; 42738032Speter if (host == NULL) 42838032Speter host = "localhost"; 42938032Speter 43038032Speter if (feof(fp)) 43138032Speter problem = "unexpected close"; 43238032Speter else if (ferror(fp)) 43338032Speter problem = "I/O error"; 43438032Speter else 43538032Speter problem = "read timeout"; 43638032Speter if (LogLevel > 0 && feof(fp)) 43738032Speter sm_syslog(LOG_NOTICE, e->e_id, 43838032Speter "collect: %s on connection from %.100s, sender=%s: %s", 43938032Speter problem, host, 44038032Speter shortenstring(e->e_from.q_paddr, MAXSHORTSTR), 44138032Speter errstring(errno)); 44238032Speter if (feof(fp)) 44338032Speter usrerr("451 collect: %s on connection from %s, from=%s", 44438032Speter problem, host, 44538032Speter shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 44638032Speter else 44738032Speter syserr("451 collect: %s on connection from %s, from=%s", 44838032Speter problem, host, 44938032Speter shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 45038032Speter 45138032Speter /* don't return an error indication */ 45238032Speter e->e_to = NULL; 45338032Speter e->e_flags &= ~EF_FATALERRS; 45438032Speter e->e_flags |= EF_CLRQUEUE; 45538032Speter 45638032Speter /* and don't try to deliver the partial message either */ 45738032Speter if (InChild) 45838032Speter ExitStat = EX_QUIT; 45938032Speter finis(); 46038032Speter } 46138032Speter 46238032Speter /* 46338032Speter ** Find out some information from the headers. 46438032Speter ** Examples are who is the from person & the date. 46538032Speter */ 46638032Speter 46738032Speter eatheader(e, TRUE); 46838032Speter 46938032Speter if (GrabTo && e->e_sendqueue == NULL) 47038032Speter usrerr("No recipient addresses found in header"); 47138032Speter 47238032Speter /* collect statistics */ 47338032Speter if (OpMode != MD_VERIFY) 47438032Speter markstats(e, (ADDRESS *) NULL, FALSE); 47538032Speter 47638032Speter#if _FFR_DSN_RRT_OPTION 47738032Speter /* 47838032Speter ** If we have a Return-Receipt-To:, turn it into a DSN. 47938032Speter */ 48038032Speter 48138032Speter if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 48238032Speter { 48338032Speter ADDRESS *q; 48438032Speter 48538032Speter for (q = e->e_sendqueue; q != NULL; q = q->q_next) 48638032Speter if (!bitset(QHASNOTIFY, q->q_flags)) 48738032Speter q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 48838032Speter } 48938032Speter#endif 49038032Speter 49138032Speter /* 49238032Speter ** Add an Apparently-To: line if we have no recipient lines. 49338032Speter */ 49438032Speter 49538032Speter if (hvalue("to", e->e_header) != NULL || 49638032Speter hvalue("cc", e->e_header) != NULL || 49738032Speter hvalue("apparently-to", e->e_header) != NULL) 49838032Speter { 49938032Speter /* have a valid recipient header -- delete Bcc: headers */ 50038032Speter e->e_flags |= EF_DELETE_BCC; 50138032Speter } 50238032Speter else if (hvalue("bcc", e->e_header) == NULL) 50338032Speter { 50438032Speter /* no valid recipient headers */ 50538032Speter register ADDRESS *q; 50638032Speter char *hdr = NULL; 50738032Speter extern void addheader __P((char *, char *, HDR **)); 50838032Speter 50938032Speter /* create an Apparently-To: field */ 51038032Speter /* that or reject the message.... */ 51138032Speter switch (NoRecipientAction) 51238032Speter { 51338032Speter case NRA_ADD_APPARENTLY_TO: 51438032Speter hdr = "Apparently-To"; 51538032Speter break; 51638032Speter 51738032Speter case NRA_ADD_TO: 51838032Speter hdr = "To"; 51938032Speter break; 52038032Speter 52138032Speter case NRA_ADD_BCC: 52238032Speter addheader("Bcc", " ", &e->e_header); 52338032Speter break; 52438032Speter 52538032Speter case NRA_ADD_TO_UNDISCLOSED: 52638032Speter addheader("To", "undisclosed-recipients:;", &e->e_header); 52738032Speter break; 52838032Speter } 52938032Speter 53038032Speter if (hdr != NULL) 53138032Speter { 53238032Speter for (q = e->e_sendqueue; q != NULL; q = q->q_next) 53338032Speter { 53438032Speter if (q->q_alias != NULL) 53538032Speter continue; 53638032Speter if (tTd(30, 3)) 53738032Speter printf("Adding %s: %s\n", 53838032Speter hdr, q->q_paddr); 53938032Speter addheader(hdr, q->q_paddr, &e->e_header); 54038032Speter } 54138032Speter } 54238032Speter } 54338032Speter 54438032Speter /* check for message too large */ 54538032Speter if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) 54638032Speter { 54738032Speter e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 54838032Speter e->e_status = "5.2.3"; 54938032Speter usrerr("552 Message exceeds maximum fixed size (%ld)", 55038032Speter MaxMessageSize); 55138032Speter if (LogLevel > 6) 55238032Speter sm_syslog(LOG_NOTICE, e->e_id, 55338032Speter "message size (%ld) exceeds maximum (%ld)", 55438032Speter e->e_msgsize, MaxMessageSize); 55538032Speter } 55638032Speter 55738032Speter /* check for illegal 8-bit data */ 55838032Speter if (HasEightBits) 55938032Speter { 56038032Speter e->e_flags |= EF_HAS8BIT; 56138032Speter if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 56238032Speter !bitset(EF_IS_MIME, e->e_flags)) 56338032Speter { 56438032Speter e->e_status = "5.6.1"; 56538032Speter usrerr("554 Eight bit data not allowed"); 56638032Speter } 56738032Speter } 56838032Speter else 56938032Speter { 57038032Speter /* if it claimed to be 8 bits, well, it lied.... */ 57138032Speter if (e->e_bodytype != NULL && 57238032Speter strcasecmp(e->e_bodytype, "8BITMIME") == 0) 57338032Speter e->e_bodytype = "7BIT"; 57438032Speter } 57538032Speter 57638032Speter if ((e->e_dfp = fopen(dfname, "r")) == NULL) 57738032Speter { 57838032Speter /* we haven't acked receipt yet, so just chuck this */ 57938032Speter syserr("Cannot reopen %s", dfname); 58038032Speter finis(); 58138032Speter } 58238032Speter} 58338032Speter 58438032Speter 58538032Speterstatic void 58638032Spetercollecttimeout(timeout) 58738032Speter time_t timeout; 58838032Speter{ 58938032Speter /* if no progress was made, die now */ 59038032Speter if (!CollectProgress) 59138032Speter longjmp(CtxCollectTimeout, 1); 59238032Speter 59338032Speter /* otherwise reset the timeout */ 59438032Speter CollectTimeout = setevent(timeout, collecttimeout, timeout); 59538032Speter CollectProgress = FALSE; 59638032Speter} 59738032Speter/* 59838032Speter** TFERROR -- signal error on writing the temporary file. 59938032Speter** 60038032Speter** Parameters: 60138032Speter** tf -- the file pointer for the temporary file. 60238032Speter** e -- the current envelope. 60338032Speter** 60438032Speter** Returns: 60538032Speter** none. 60638032Speter** 60738032Speter** Side Effects: 60838032Speter** Gives an error message. 60938032Speter** Arranges for following output to go elsewhere. 61038032Speter*/ 61138032Speter 61238032Spetervoid 61338032Spetertferror(tf, e) 61438032Speter FILE *volatile tf; 61538032Speter register ENVELOPE *e; 61638032Speter{ 61738032Speter setstat(EX_IOERR); 61838032Speter if (errno == ENOSPC) 61938032Speter { 62038032Speter#if STAT64 > 0 62138032Speter struct stat64 st; 62238032Speter#else 62338032Speter struct stat st; 62438032Speter#endif 62538032Speter long avail; 62638032Speter long bsize; 62738032Speter extern long freediskspace __P((char *, long *)); 62838032Speter 62938032Speter e->e_flags |= EF_NO_BODY_RETN; 63038032Speter 63138032Speter if ( 63238032Speter#if STAT64 > 0 63338032Speter fstat64(fileno(tf), &st) 63438032Speter#else 63538032Speter fstat(fileno(tf), &st) 63638032Speter#endif 63738032Speter < 0) 63838032Speter st.st_size = 0; 63938032Speter (void) freopen(queuename(e, 'd'), "w", tf); 64038032Speter if (st.st_size <= 0) 64138032Speter fprintf(tf, "\n*** Mail could not be accepted"); 64238032Speter else if (sizeof st.st_size > sizeof (long)) 64338032Speter fprintf(tf, "\n*** Mail of at least %s bytes could not be accepted\n", 64438032Speter quad_to_string(st.st_size)); 64538032Speter else 64638032Speter fprintf(tf, "\n*** Mail of at least %lu bytes could not be accepted\n", 64738032Speter (unsigned long) st.st_size); 64838032Speter fprintf(tf, "*** at %s due to lack of disk space for temp file.\n", 64938032Speter MyHostName); 65038032Speter avail = freediskspace(QueueDir, &bsize); 65138032Speter if (avail > 0) 65238032Speter { 65338032Speter if (bsize > 1024) 65438032Speter avail *= bsize / 1024; 65538032Speter else if (bsize < 1024) 65638032Speter avail /= 1024 / bsize; 65738032Speter fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n", 65838032Speter avail); 65938032Speter } 66038032Speter e->e_status = "4.3.1"; 66138032Speter usrerr("452 Out of disk space for temp file"); 66238032Speter } 66338032Speter else 66438032Speter syserr("collect: Cannot write tf%s", e->e_id); 66538032Speter if (freopen("/dev/null", "w", tf) == NULL) 66638032Speter sm_syslog(LOG_ERR, e->e_id, 66738032Speter "tferror: freopen(\"/dev/null\") failed: %s", 66838032Speter errstring(errno)); 66938032Speter} 67038032Speter/* 67138032Speter** EATFROM -- chew up a UNIX style from line and process 67238032Speter** 67338032Speter** This does indeed make some assumptions about the format 67438032Speter** of UNIX messages. 67538032Speter** 67638032Speter** Parameters: 67738032Speter** fm -- the from line. 67838032Speter** 67938032Speter** Returns: 68038032Speter** none. 68138032Speter** 68238032Speter** Side Effects: 68338032Speter** extracts what information it can from the header, 68438032Speter** such as the date. 68538032Speter*/ 68638032Speter 68738032Speter# ifndef NOTUNIX 68838032Speter 68938032Speterchar *DowList[] = 69038032Speter{ 69138032Speter "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 69238032Speter}; 69338032Speter 69438032Speterchar *MonthList[] = 69538032Speter{ 69638032Speter "Jan", "Feb", "Mar", "Apr", "May", "Jun", 69738032Speter "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 69838032Speter NULL 69938032Speter}; 70038032Speter 70138032Spetervoid 70238032Spetereatfrom(fm, e) 70338032Speter char *volatile fm; 70438032Speter register ENVELOPE *e; 70538032Speter{ 70638032Speter register char *p; 70738032Speter register char **dt; 70838032Speter 70938032Speter if (tTd(30, 2)) 71038032Speter printf("eatfrom(%s)\n", fm); 71138032Speter 71238032Speter /* find the date part */ 71338032Speter p = fm; 71438032Speter while (*p != '\0') 71538032Speter { 71638032Speter /* skip a word */ 71738032Speter while (*p != '\0' && *p != ' ') 71838032Speter p++; 71938032Speter while (*p == ' ') 72038032Speter p++; 72138032Speter if (!(isascii(*p) && isupper(*p)) || 72238032Speter p[3] != ' ' || p[13] != ':' || p[16] != ':') 72338032Speter continue; 72438032Speter 72538032Speter /* we have a possible date */ 72638032Speter for (dt = DowList; *dt != NULL; dt++) 72738032Speter if (strncmp(*dt, p, 3) == 0) 72838032Speter break; 72938032Speter if (*dt == NULL) 73038032Speter continue; 73138032Speter 73238032Speter for (dt = MonthList; *dt != NULL; dt++) 73338032Speter if (strncmp(*dt, &p[4], 3) == 0) 73438032Speter break; 73538032Speter if (*dt != NULL) 73638032Speter break; 73738032Speter } 73838032Speter 73938032Speter if (*p != '\0') 74038032Speter { 74138032Speter char *q; 74238032Speter 74338032Speter /* we have found a date */ 74438032Speter q = xalloc(25); 74538032Speter (void) strncpy(q, p, 25); 74638032Speter q[24] = '\0'; 74738032Speter q = arpadate(q); 74838032Speter define('a', newstr(q), e); 74938032Speter } 75038032Speter} 75138032Speter 75238032Speter# endif /* NOTUNIX */ 753