1c2aa98e2SPeter Wemm /* 2602a2b1bSGregory Neil Shapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 14c2aa98e2SPeter Wemm #ifndef lint 158774250cSGregory Neil Shapiro static char id[] = "@(#)$Id: collect.c,v 8.136.4.21 2001/05/17 18:10:14 gshapiro Exp $"; 1606f25ae9SGregory Neil Shapiro #endif /* ! lint */ 17c2aa98e2SPeter Wemm 1806f25ae9SGregory Neil Shapiro #include <sendmail.h> 19c2aa98e2SPeter Wemm 2006f25ae9SGregory Neil Shapiro 2106f25ae9SGregory Neil Shapiro static void collecttimeout __P((time_t)); 2206f25ae9SGregory Neil Shapiro static void dferror __P((FILE *volatile, char *, ENVELOPE *)); 2306f25ae9SGregory Neil Shapiro static void eatfrom __P((char *volatile, ENVELOPE *)); 2406f25ae9SGregory Neil Shapiro 2506f25ae9SGregory Neil Shapiro /* 26c2aa98e2SPeter Wemm ** COLLECT -- read & parse message header & make temp file. 27c2aa98e2SPeter Wemm ** 28c2aa98e2SPeter Wemm ** Creates a temporary file name and copies the standard 29c2aa98e2SPeter Wemm ** input to that file. Leading UNIX-style "From" lines are 30c2aa98e2SPeter Wemm ** stripped off (after important information is extracted). 31c2aa98e2SPeter Wemm ** 32c2aa98e2SPeter Wemm ** Parameters: 33c2aa98e2SPeter Wemm ** fp -- file to read. 34c2aa98e2SPeter Wemm ** smtpmode -- if set, we are running SMTP: give an RFC821 35c2aa98e2SPeter Wemm ** style message to say we are ready to collect 36c2aa98e2SPeter Wemm ** input, and never ignore a single dot to mean 37c2aa98e2SPeter Wemm ** end of message. 38c2aa98e2SPeter Wemm ** hdrp -- the location to stash the header. 39c2aa98e2SPeter Wemm ** e -- the current envelope. 40c2aa98e2SPeter Wemm ** 41c2aa98e2SPeter Wemm ** Returns: 42c2aa98e2SPeter Wemm ** none. 43c2aa98e2SPeter Wemm ** 44c2aa98e2SPeter Wemm ** Side Effects: 45c2aa98e2SPeter Wemm ** Temp file is created and filled. 46c2aa98e2SPeter Wemm ** The from person may be set. 47c2aa98e2SPeter Wemm */ 48c2aa98e2SPeter Wemm 49c2aa98e2SPeter Wemm static jmp_buf CtxCollectTimeout; 508774250cSGregory Neil Shapiro static bool volatile CollectProgress; 518774250cSGregory Neil Shapiro static EVENT *volatile CollectTimeout = NULL; 52c2aa98e2SPeter Wemm 53c2aa98e2SPeter Wemm /* values for input state machine */ 54c2aa98e2SPeter Wemm #define IS_NORM 0 /* middle of line */ 55c2aa98e2SPeter Wemm #define IS_BOL 1 /* beginning of line */ 56c2aa98e2SPeter Wemm #define IS_DOT 2 /* read a dot at beginning of line */ 57c2aa98e2SPeter Wemm #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 58c2aa98e2SPeter Wemm #define IS_CR 4 /* read a carriage return */ 59c2aa98e2SPeter Wemm 60c2aa98e2SPeter Wemm /* values for message state machine */ 61c2aa98e2SPeter Wemm #define MS_UFROM 0 /* reading Unix from line */ 62c2aa98e2SPeter Wemm #define MS_HEADER 1 /* reading message header */ 63c2aa98e2SPeter Wemm #define MS_BODY 2 /* reading message body */ 6425bab6e9SPeter Wemm #define MS_DISCARD 3 /* discarding rest of message */ 65c2aa98e2SPeter Wemm 66c2aa98e2SPeter Wemm void 67c2aa98e2SPeter Wemm collect(fp, smtpmode, hdrp, e) 68c2aa98e2SPeter Wemm FILE *fp; 69c2aa98e2SPeter Wemm bool smtpmode; 70c2aa98e2SPeter Wemm HDR **hdrp; 71c2aa98e2SPeter Wemm register ENVELOPE *e; 72c2aa98e2SPeter Wemm { 7306f25ae9SGregory Neil Shapiro register FILE *volatile df; 74c2aa98e2SPeter Wemm volatile bool ignrdot = smtpmode ? FALSE : IgnrDot; 75c2aa98e2SPeter Wemm volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; 76c2aa98e2SPeter Wemm register char *volatile bp; 77c2aa98e2SPeter Wemm volatile int c = EOF; 78c2aa98e2SPeter Wemm volatile bool inputerr = FALSE; 79c2aa98e2SPeter Wemm bool headeronly; 80c2aa98e2SPeter Wemm char *volatile buf; 81c2aa98e2SPeter Wemm volatile int buflen; 82c2aa98e2SPeter Wemm volatile int istate; 83c2aa98e2SPeter Wemm volatile int mstate; 8406f25ae9SGregory Neil Shapiro volatile int hdrslen = 0; 8506f25ae9SGregory Neil Shapiro volatile int numhdrs = 0; 8606f25ae9SGregory Neil Shapiro volatile int dfd; 8706f25ae9SGregory Neil Shapiro volatile int rstat = EX_OK; 88c2aa98e2SPeter Wemm u_char *volatile pbp; 89c2aa98e2SPeter Wemm u_char peekbuf[8]; 9006f25ae9SGregory Neil Shapiro char hsize[16]; 9106f25ae9SGregory Neil Shapiro char hnum[16]; 9206f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN]; 93c2aa98e2SPeter Wemm char bufbuf[MAXLINE]; 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 96c2aa98e2SPeter Wemm 97c2aa98e2SPeter Wemm /* 98c2aa98e2SPeter Wemm ** Create the temp file name and create the file. 99c2aa98e2SPeter Wemm */ 100c2aa98e2SPeter Wemm 101c2aa98e2SPeter Wemm if (!headeronly) 102c2aa98e2SPeter Wemm { 103c2aa98e2SPeter Wemm struct stat stbuf; 104602a2b1bSGregory Neil Shapiro long sff = SFF_OPENASROOT; 105602a2b1bSGregory Neil Shapiro 106c2aa98e2SPeter Wemm 10706f25ae9SGregory Neil Shapiro (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); 10806f25ae9SGregory Neil Shapiro #if _FFR_QUEUE_FILE_MODE 10906f25ae9SGregory Neil Shapiro { 11006f25ae9SGregory Neil Shapiro MODE_T oldumask; 11106f25ae9SGregory Neil Shapiro 11206f25ae9SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 11306f25ae9SGregory Neil Shapiro oldumask = umask(002); 114602a2b1bSGregory Neil Shapiro df = bfopen(dfname, QueueFileMode, 115602a2b1bSGregory Neil Shapiro DataFileBufferSize, sff); 11606f25ae9SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 11706f25ae9SGregory Neil Shapiro (void) umask(oldumask); 11806f25ae9SGregory Neil Shapiro } 11906f25ae9SGregory Neil Shapiro #else /* _FFR_QUEUE_FILE_MODE */ 120602a2b1bSGregory Neil Shapiro df = bfopen(dfname, FileMode, DataFileBufferSize, sff); 12106f25ae9SGregory Neil Shapiro #endif /* _FFR_QUEUE_FILE_MODE */ 12206f25ae9SGregory Neil Shapiro if (df == NULL) 123c2aa98e2SPeter Wemm { 124602a2b1bSGregory Neil Shapiro HoldErrs = FALSE; 125602a2b1bSGregory Neil Shapiro if (smtpmode) 126602a2b1bSGregory Neil Shapiro syserr("421 4.3.5 Unable to create data file"); 127602a2b1bSGregory Neil Shapiro else 128c2aa98e2SPeter Wemm syserr("Cannot create %s", dfname); 129c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 130065a643dSPeter Wemm finis(TRUE, ExitStat); 13106f25ae9SGregory Neil Shapiro /* NOTREACHED */ 132c2aa98e2SPeter Wemm } 13306f25ae9SGregory Neil Shapiro dfd = fileno(df); 13406f25ae9SGregory Neil Shapiro if (dfd < 0 || fstat(dfd, &stbuf) < 0) 135c2aa98e2SPeter Wemm e->e_dfino = -1; 136c2aa98e2SPeter Wemm else 137c2aa98e2SPeter Wemm { 138c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev; 139c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino; 140c2aa98e2SPeter Wemm } 141c2aa98e2SPeter Wemm HasEightBits = FALSE; 142c2aa98e2SPeter Wemm e->e_msgsize = 0; 143c2aa98e2SPeter Wemm e->e_flags |= EF_HAS_DF; 144c2aa98e2SPeter Wemm } 145c2aa98e2SPeter Wemm 146c2aa98e2SPeter Wemm /* 147c2aa98e2SPeter Wemm ** Tell ARPANET to go ahead. 148c2aa98e2SPeter Wemm */ 149c2aa98e2SPeter Wemm 150c2aa98e2SPeter Wemm if (smtpmode) 151c2aa98e2SPeter Wemm message("354 Enter mail, end with \".\" on a line by itself"); 152c2aa98e2SPeter Wemm 153c2aa98e2SPeter Wemm if (tTd(30, 2)) 15406f25ae9SGregory Neil Shapiro dprintf("collect\n"); 155c2aa98e2SPeter Wemm 156c2aa98e2SPeter Wemm /* 157c2aa98e2SPeter Wemm ** Read the message. 158c2aa98e2SPeter Wemm ** 159c2aa98e2SPeter Wemm ** This is done using two interleaved state machines. 160c2aa98e2SPeter Wemm ** The input state machine is looking for things like 161c2aa98e2SPeter Wemm ** hidden dots; the message state machine is handling 162c2aa98e2SPeter Wemm ** the larger picture (e.g., header versus body). 163c2aa98e2SPeter Wemm */ 164c2aa98e2SPeter Wemm 165c2aa98e2SPeter Wemm buf = bp = bufbuf; 166c2aa98e2SPeter Wemm buflen = sizeof bufbuf; 167c2aa98e2SPeter Wemm pbp = peekbuf; 168c2aa98e2SPeter Wemm istate = IS_BOL; 169c2aa98e2SPeter Wemm mstate = SaveFrom ? MS_HEADER : MS_UFROM; 170c2aa98e2SPeter Wemm CollectProgress = FALSE; 171c2aa98e2SPeter Wemm 172c2aa98e2SPeter Wemm if (dbto != 0) 173c2aa98e2SPeter Wemm { 174c2aa98e2SPeter Wemm /* handle possible input timeout */ 175c2aa98e2SPeter Wemm if (setjmp(CtxCollectTimeout) != 0) 176c2aa98e2SPeter Wemm { 177c2aa98e2SPeter Wemm if (LogLevel > 2) 178c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 179c2aa98e2SPeter Wemm "timeout waiting for input from %s during message collect", 180c2aa98e2SPeter Wemm CurHostName ? CurHostName : "<local machine>"); 181c2aa98e2SPeter Wemm errno = 0; 18206f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 timeout waiting for input during message collect"); 183c2aa98e2SPeter Wemm goto readerr; 184c2aa98e2SPeter Wemm } 185c2aa98e2SPeter Wemm CollectTimeout = setevent(dbto, collecttimeout, dbto); 186c2aa98e2SPeter Wemm } 187c2aa98e2SPeter Wemm 188c2aa98e2SPeter Wemm for (;;) 189c2aa98e2SPeter Wemm { 190c2aa98e2SPeter Wemm if (tTd(30, 35)) 19106f25ae9SGregory Neil Shapiro dprintf("top, istate=%d, mstate=%d\n", istate, mstate); 192c2aa98e2SPeter Wemm for (;;) 193c2aa98e2SPeter Wemm { 194c2aa98e2SPeter Wemm if (pbp > peekbuf) 195c2aa98e2SPeter Wemm c = *--pbp; 196c2aa98e2SPeter Wemm else 197c2aa98e2SPeter Wemm { 198c2aa98e2SPeter Wemm while (!feof(fp) && !ferror(fp)) 199c2aa98e2SPeter Wemm { 200c2aa98e2SPeter Wemm errno = 0; 201c2aa98e2SPeter Wemm c = getc(fp); 20242e5d165SGregory Neil Shapiro 20342e5d165SGregory Neil Shapiro if (c == EOF && errno == EINTR) 20442e5d165SGregory Neil Shapiro { 20542e5d165SGregory Neil Shapiro /* Interrupted, retry */ 206c2aa98e2SPeter Wemm clearerr(fp); 20742e5d165SGregory Neil Shapiro continue; 20842e5d165SGregory Neil Shapiro } 20942e5d165SGregory Neil Shapiro break; 210c2aa98e2SPeter Wemm } 211c2aa98e2SPeter Wemm CollectProgress = TRUE; 212c2aa98e2SPeter Wemm if (TrafficLogFile != NULL && !headeronly) 213c2aa98e2SPeter Wemm { 214c2aa98e2SPeter Wemm if (istate == IS_BOL) 2158774250cSGregory Neil Shapiro (void) fprintf(TrafficLogFile, 2168774250cSGregory Neil Shapiro "%05d <<< ", 217c2aa98e2SPeter Wemm (int) getpid()); 218c2aa98e2SPeter Wemm if (c == EOF) 2198774250cSGregory Neil Shapiro (void) fprintf(TrafficLogFile, 2208774250cSGregory Neil Shapiro "[EOF]\n"); 221c2aa98e2SPeter Wemm else 22206f25ae9SGregory Neil Shapiro (void) putc(c, TrafficLogFile); 223c2aa98e2SPeter Wemm } 224c2aa98e2SPeter Wemm if (c == EOF) 225c2aa98e2SPeter Wemm goto readerr; 226c2aa98e2SPeter Wemm if (SevenBitInput) 227c2aa98e2SPeter Wemm c &= 0x7f; 228c2aa98e2SPeter Wemm else 229c2aa98e2SPeter Wemm HasEightBits |= bitset(0x80, c); 230c2aa98e2SPeter Wemm } 231c2aa98e2SPeter Wemm if (tTd(30, 94)) 23206f25ae9SGregory Neil Shapiro dprintf("istate=%d, c=%c (0x%x)\n", 23306f25ae9SGregory Neil Shapiro istate, (char) c, c); 234c2aa98e2SPeter Wemm switch (istate) 235c2aa98e2SPeter Wemm { 236c2aa98e2SPeter Wemm case IS_BOL: 237c2aa98e2SPeter Wemm if (c == '.') 238c2aa98e2SPeter Wemm { 239c2aa98e2SPeter Wemm istate = IS_DOT; 240c2aa98e2SPeter Wemm continue; 241c2aa98e2SPeter Wemm } 242c2aa98e2SPeter Wemm break; 243c2aa98e2SPeter Wemm 244c2aa98e2SPeter Wemm case IS_DOT: 245c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot && 246c2aa98e2SPeter Wemm !bitset(EF_NL_NOT_EOL, e->e_flags)) 247c2aa98e2SPeter Wemm goto readerr; 248c2aa98e2SPeter Wemm else if (c == '\r' && 249c2aa98e2SPeter Wemm !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 250c2aa98e2SPeter Wemm { 251c2aa98e2SPeter Wemm istate = IS_DOTCR; 252c2aa98e2SPeter Wemm continue; 253c2aa98e2SPeter Wemm } 254c2aa98e2SPeter Wemm else if (c != '.' || 255c2aa98e2SPeter Wemm (OpMode != MD_SMTP && 256c2aa98e2SPeter Wemm OpMode != MD_DAEMON && 257c2aa98e2SPeter Wemm OpMode != MD_ARPAFTP)) 258c2aa98e2SPeter Wemm { 259c2aa98e2SPeter Wemm *pbp++ = c; 260c2aa98e2SPeter Wemm c = '.'; 261c2aa98e2SPeter Wemm } 262c2aa98e2SPeter Wemm break; 263c2aa98e2SPeter Wemm 264c2aa98e2SPeter Wemm case IS_DOTCR: 265c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot) 266c2aa98e2SPeter Wemm goto readerr; 267c2aa98e2SPeter Wemm else 268c2aa98e2SPeter Wemm { 269c2aa98e2SPeter Wemm /* push back the ".\rx" */ 270c2aa98e2SPeter Wemm *pbp++ = c; 271c2aa98e2SPeter Wemm *pbp++ = '\r'; 272c2aa98e2SPeter Wemm c = '.'; 273c2aa98e2SPeter Wemm } 274c2aa98e2SPeter Wemm break; 275c2aa98e2SPeter Wemm 276c2aa98e2SPeter Wemm case IS_CR: 277c2aa98e2SPeter Wemm if (c == '\n') 278c2aa98e2SPeter Wemm istate = IS_BOL; 279c2aa98e2SPeter Wemm else 280c2aa98e2SPeter Wemm { 28106f25ae9SGregory Neil Shapiro (void) ungetc(c, fp); 282c2aa98e2SPeter Wemm c = '\r'; 283c2aa98e2SPeter Wemm istate = IS_NORM; 284c2aa98e2SPeter Wemm } 285c2aa98e2SPeter Wemm goto bufferchar; 286c2aa98e2SPeter Wemm } 287c2aa98e2SPeter Wemm 288c2aa98e2SPeter Wemm if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 289c2aa98e2SPeter Wemm { 290c2aa98e2SPeter Wemm istate = IS_CR; 291c2aa98e2SPeter Wemm continue; 292c2aa98e2SPeter Wemm } 293c2aa98e2SPeter Wemm else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 294c2aa98e2SPeter Wemm istate = IS_BOL; 295c2aa98e2SPeter Wemm else 296c2aa98e2SPeter Wemm istate = IS_NORM; 297c2aa98e2SPeter Wemm 298c2aa98e2SPeter Wemm bufferchar: 299c2aa98e2SPeter Wemm if (!headeronly) 30042e5d165SGregory Neil Shapiro { 30142e5d165SGregory Neil Shapiro /* no overflow? */ 30242e5d165SGregory Neil Shapiro if (e->e_msgsize >= 0) 30342e5d165SGregory Neil Shapiro { 304c2aa98e2SPeter Wemm e->e_msgsize++; 30542e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 && 30642e5d165SGregory Neil Shapiro !bitset(EF_TOOBIG, e->e_flags) && 30742e5d165SGregory Neil Shapiro e->e_msgsize > MaxMessageSize) 30842e5d165SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 30942e5d165SGregory Neil Shapiro } 31042e5d165SGregory Neil Shapiro } 31125bab6e9SPeter Wemm switch (mstate) 312c2aa98e2SPeter Wemm { 31325bab6e9SPeter Wemm case MS_BODY: 314c2aa98e2SPeter Wemm /* just put the character out */ 31542e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 31606f25ae9SGregory Neil Shapiro (void) putc(c, df); 31706f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 31825bab6e9SPeter Wemm 31925bab6e9SPeter Wemm case MS_DISCARD: 320c2aa98e2SPeter Wemm continue; 321c2aa98e2SPeter Wemm } 322c2aa98e2SPeter Wemm 323c2aa98e2SPeter Wemm /* header -- buffer up */ 324c2aa98e2SPeter Wemm if (bp >= &buf[buflen - 2]) 325c2aa98e2SPeter Wemm { 326c2aa98e2SPeter Wemm char *obuf; 327c2aa98e2SPeter Wemm 328c2aa98e2SPeter Wemm if (mstate != MS_HEADER) 329c2aa98e2SPeter Wemm break; 330c2aa98e2SPeter Wemm 331c2aa98e2SPeter Wemm /* out of space for header */ 332c2aa98e2SPeter Wemm obuf = buf; 333c2aa98e2SPeter Wemm if (buflen < MEMCHUNKSIZE) 334c2aa98e2SPeter Wemm buflen *= 2; 335c2aa98e2SPeter Wemm else 336c2aa98e2SPeter Wemm buflen += MEMCHUNKSIZE; 337c2aa98e2SPeter Wemm buf = xalloc(buflen); 33806f25ae9SGregory Neil Shapiro memmove(buf, obuf, bp - obuf); 339c2aa98e2SPeter Wemm bp = &buf[bp - obuf]; 340c2aa98e2SPeter Wemm if (obuf != bufbuf) 3418774250cSGregory Neil Shapiro sm_free(obuf); 342c2aa98e2SPeter Wemm } 343c2aa98e2SPeter Wemm if (c >= 0200 && c <= 0237) 344c2aa98e2SPeter Wemm { 34506f25ae9SGregory Neil Shapiro #if 0 /* causes complaints -- figure out something for 8.11 */ 346c2aa98e2SPeter Wemm usrerr("Illegal character 0x%x in header", c); 34706f25ae9SGregory Neil Shapiro #else /* 0 */ 34806f25ae9SGregory Neil Shapiro /* EMPTY */ 34906f25ae9SGregory Neil Shapiro #endif /* 0 */ 350c2aa98e2SPeter Wemm } 351c2aa98e2SPeter Wemm else if (c != '\0') 35225bab6e9SPeter Wemm { 353c2aa98e2SPeter Wemm *bp++ = c; 354602a2b1bSGregory Neil Shapiro hdrslen++; 3552e43090eSPeter Wemm if (MaxHeadersLength > 0 && 356602a2b1bSGregory Neil Shapiro hdrslen > MaxHeadersLength) 35725bab6e9SPeter Wemm { 35825bab6e9SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 3592e43090eSPeter Wemm "headers too large (%d max) from %s during message collect", 3602e43090eSPeter Wemm MaxHeadersLength, 36125bab6e9SPeter Wemm CurHostName != NULL ? CurHostName : "localhost"); 36225bab6e9SPeter Wemm errno = 0; 36325bab6e9SPeter Wemm e->e_flags |= EF_CLRQUEUE; 36425bab6e9SPeter Wemm e->e_status = "5.6.0"; 36506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 36606f25ae9SGregory Neil Shapiro "552 Headers too large (%d max)", 3672e43090eSPeter Wemm MaxHeadersLength); 36825bab6e9SPeter Wemm mstate = MS_DISCARD; 36925bab6e9SPeter Wemm } 37025bab6e9SPeter Wemm } 371c2aa98e2SPeter Wemm if (istate == IS_BOL) 372c2aa98e2SPeter Wemm break; 373c2aa98e2SPeter Wemm } 374c2aa98e2SPeter Wemm *bp = '\0'; 375c2aa98e2SPeter Wemm 376c2aa98e2SPeter Wemm nextstate: 377c2aa98e2SPeter Wemm if (tTd(30, 35)) 37806f25ae9SGregory Neil Shapiro dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 379c2aa98e2SPeter Wemm istate, mstate, buf); 380c2aa98e2SPeter Wemm switch (mstate) 381c2aa98e2SPeter Wemm { 382c2aa98e2SPeter Wemm case MS_UFROM: 383c2aa98e2SPeter Wemm mstate = MS_HEADER; 384c2aa98e2SPeter Wemm #ifndef NOTUNIX 385c2aa98e2SPeter Wemm if (strncmp(buf, "From ", 5) == 0) 386c2aa98e2SPeter Wemm { 387c2aa98e2SPeter Wemm bp = buf; 388c2aa98e2SPeter Wemm eatfrom(buf, e); 389c2aa98e2SPeter Wemm continue; 390c2aa98e2SPeter Wemm } 39106f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 39206f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 393c2aa98e2SPeter Wemm 394c2aa98e2SPeter Wemm case MS_HEADER: 395c2aa98e2SPeter Wemm if (!isheader(buf)) 396c2aa98e2SPeter Wemm { 397c2aa98e2SPeter Wemm mstate = MS_BODY; 398c2aa98e2SPeter Wemm goto nextstate; 399c2aa98e2SPeter Wemm } 400c2aa98e2SPeter Wemm 401c2aa98e2SPeter Wemm /* check for possible continuation line */ 402c2aa98e2SPeter Wemm do 403c2aa98e2SPeter Wemm { 404c2aa98e2SPeter Wemm clearerr(fp); 405c2aa98e2SPeter Wemm errno = 0; 406c2aa98e2SPeter Wemm c = getc(fp); 40742e5d165SGregory Neil Shapiro } while (c == EOF && errno == EINTR); 408c2aa98e2SPeter Wemm if (c != EOF) 40906f25ae9SGregory Neil Shapiro (void) ungetc(c, fp); 410c2aa98e2SPeter Wemm if (c == ' ' || c == '\t') 411c2aa98e2SPeter Wemm { 412c2aa98e2SPeter Wemm /* yep -- defer this */ 413c2aa98e2SPeter Wemm continue; 414c2aa98e2SPeter Wemm } 415c2aa98e2SPeter Wemm 416c2aa98e2SPeter Wemm /* trim off trailing CRLF or NL */ 417c2aa98e2SPeter Wemm if (*--bp != '\n' || *--bp != '\r') 418c2aa98e2SPeter Wemm bp++; 419c2aa98e2SPeter Wemm *bp = '\0'; 42025bab6e9SPeter Wemm 42106f25ae9SGregory Neil Shapiro if (bitset(H_EOH, chompheader(buf, 42206f25ae9SGregory Neil Shapiro CHHDR_CHECK | CHHDR_USER, 42306f25ae9SGregory Neil Shapiro hdrp, e))) 424c2aa98e2SPeter Wemm { 425c2aa98e2SPeter Wemm mstate = MS_BODY; 426c2aa98e2SPeter Wemm goto nextstate; 427c2aa98e2SPeter Wemm } 42806f25ae9SGregory Neil Shapiro numhdrs++; 429c2aa98e2SPeter Wemm break; 430c2aa98e2SPeter Wemm 431c2aa98e2SPeter Wemm case MS_BODY: 432c2aa98e2SPeter Wemm if (tTd(30, 1)) 43306f25ae9SGregory Neil Shapiro dprintf("EOH\n"); 43406f25ae9SGregory Neil Shapiro 435c2aa98e2SPeter Wemm if (headeronly) 436c2aa98e2SPeter Wemm goto readerr; 43706f25ae9SGregory Neil Shapiro 43806f25ae9SGregory Neil Shapiro /* call the end-of-header check ruleset */ 43906f25ae9SGregory Neil Shapiro snprintf(hnum, sizeof hnum, "%d", numhdrs); 44006f25ae9SGregory Neil Shapiro snprintf(hsize, sizeof hsize, "%d", hdrslen); 44106f25ae9SGregory Neil Shapiro if (tTd(30, 10)) 44206f25ae9SGregory Neil Shapiro dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 44306f25ae9SGregory Neil Shapiro hnum, hsize); 44406f25ae9SGregory Neil Shapiro rstat = rscheck("check_eoh", hnum, hsize, e, FALSE, 445193538b7SGregory Neil Shapiro TRUE, 4, NULL); 44606f25ae9SGregory Neil Shapiro 447c2aa98e2SPeter Wemm bp = buf; 448c2aa98e2SPeter Wemm 449c2aa98e2SPeter Wemm /* toss blank line */ 450c2aa98e2SPeter Wemm if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 451c2aa98e2SPeter Wemm bp[0] == '\r' && bp[1] == '\n') || 452c2aa98e2SPeter Wemm (!bitset(EF_NL_NOT_EOL, e->e_flags) && 453c2aa98e2SPeter Wemm bp[0] == '\n')) 454c2aa98e2SPeter Wemm { 455c2aa98e2SPeter Wemm break; 456c2aa98e2SPeter Wemm } 457c2aa98e2SPeter Wemm 458c2aa98e2SPeter Wemm /* if not a blank separator, write it out */ 45942e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 460c2aa98e2SPeter Wemm { 461c2aa98e2SPeter Wemm while (*bp != '\0') 46206f25ae9SGregory Neil Shapiro (void) putc(*bp++, df); 463c2aa98e2SPeter Wemm } 464c2aa98e2SPeter Wemm break; 465c2aa98e2SPeter Wemm } 466c2aa98e2SPeter Wemm bp = buf; 467c2aa98e2SPeter Wemm } 468c2aa98e2SPeter Wemm 469c2aa98e2SPeter Wemm readerr: 470c2aa98e2SPeter Wemm if ((feof(fp) && smtpmode) || ferror(fp)) 471c2aa98e2SPeter Wemm { 472c2aa98e2SPeter Wemm const char *errmsg = errstring(errno); 473c2aa98e2SPeter Wemm 474c2aa98e2SPeter Wemm if (tTd(30, 1)) 47506f25ae9SGregory Neil Shapiro dprintf("collect: premature EOM: %s\n", errmsg); 476c2aa98e2SPeter Wemm if (LogLevel >= 2) 477c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 478c2aa98e2SPeter Wemm "collect: premature EOM: %s", errmsg); 479c2aa98e2SPeter Wemm inputerr = TRUE; 480c2aa98e2SPeter Wemm } 481c2aa98e2SPeter Wemm 482c2aa98e2SPeter Wemm /* reset global timer */ 4838774250cSGregory Neil Shapiro if (CollectTimeout != NULL) 484c2aa98e2SPeter Wemm clrevent(CollectTimeout); 485c2aa98e2SPeter Wemm 486c2aa98e2SPeter Wemm if (headeronly) 487c2aa98e2SPeter Wemm return; 488c2aa98e2SPeter Wemm 48906f25ae9SGregory Neil Shapiro if (df == NULL) 490c2aa98e2SPeter Wemm { 49106f25ae9SGregory Neil Shapiro /* skip next few clauses */ 49206f25ae9SGregory Neil Shapiro /* EMPTY */ 49306f25ae9SGregory Neil Shapiro } 49406f25ae9SGregory Neil Shapiro else if (fflush(df) != 0 || ferror(df)) 49506f25ae9SGregory Neil Shapiro { 49606f25ae9SGregory Neil Shapiro dferror(df, "fflush||ferror", e); 497c2aa98e2SPeter Wemm flush_errors(TRUE); 498065a643dSPeter Wemm finis(TRUE, ExitStat); 49906f25ae9SGregory Neil Shapiro /* NOTREACHED */ 50006f25ae9SGregory Neil Shapiro } 50106f25ae9SGregory Neil Shapiro else if (!SuperSafe) 50206f25ae9SGregory Neil Shapiro { 50306f25ae9SGregory Neil Shapiro /* skip next few clauses */ 50406f25ae9SGregory Neil Shapiro /* EMPTY */ 50506f25ae9SGregory Neil Shapiro } 50606f25ae9SGregory Neil Shapiro else if (bfcommit(df) < 0) 50706f25ae9SGregory Neil Shapiro { 50806f25ae9SGregory Neil Shapiro int save_errno = errno; 50906f25ae9SGregory Neil Shapiro 51006f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 51106f25ae9SGregory Neil Shapiro { 51206f25ae9SGregory Neil Shapiro char *dfile; 51306f25ae9SGregory Neil Shapiro struct stat st; 51406f25ae9SGregory Neil Shapiro 51506f25ae9SGregory Neil Shapiro dfile = queuename(e, 'd'); 51606f25ae9SGregory Neil Shapiro if (stat(dfile, &st) < 0) 51706f25ae9SGregory Neil Shapiro st.st_size = -1; 51806f25ae9SGregory Neil Shapiro errno = EEXIST; 51906f25ae9SGregory Neil Shapiro syserr("collect: bfcommit(%s): already on disk, size = %ld", 52042e5d165SGregory Neil Shapiro dfile, (long) st.st_size); 52106f25ae9SGregory Neil Shapiro dfd = fileno(df); 52206f25ae9SGregory Neil Shapiro if (dfd >= 0) 52306f25ae9SGregory Neil Shapiro dumpfd(dfd, TRUE, TRUE); 52406f25ae9SGregory Neil Shapiro } 52506f25ae9SGregory Neil Shapiro errno = save_errno; 52606f25ae9SGregory Neil Shapiro dferror(df, "bfcommit", e); 52706f25ae9SGregory Neil Shapiro flush_errors(TRUE); 52806f25ae9SGregory Neil Shapiro finis(save_errno != EEXIST, ExitStat); 52906f25ae9SGregory Neil Shapiro } 530602a2b1bSGregory Neil Shapiro else if (bffsync(df) < 0) 531602a2b1bSGregory Neil Shapiro { 532602a2b1bSGregory Neil Shapiro dferror(df, "bffsync", e); 533602a2b1bSGregory Neil Shapiro flush_errors(TRUE); 534602a2b1bSGregory Neil Shapiro finis(TRUE, ExitStat); 535602a2b1bSGregory Neil Shapiro /* NOTREACHED */ 536602a2b1bSGregory Neil Shapiro } 53706f25ae9SGregory Neil Shapiro else if (bfclose(df) < 0) 53806f25ae9SGregory Neil Shapiro { 53906f25ae9SGregory Neil Shapiro dferror(df, "bfclose", e); 54006f25ae9SGregory Neil Shapiro flush_errors(TRUE); 54106f25ae9SGregory Neil Shapiro finis(TRUE, ExitStat); 54206f25ae9SGregory Neil Shapiro /* NOTREACHED */ 54306f25ae9SGregory Neil Shapiro } 54406f25ae9SGregory Neil Shapiro else 54506f25ae9SGregory Neil Shapiro { 54606f25ae9SGregory Neil Shapiro /* everything is happily flushed to disk */ 54706f25ae9SGregory Neil Shapiro df = NULL; 548c2aa98e2SPeter Wemm } 549c2aa98e2SPeter Wemm 550c2aa98e2SPeter Wemm /* An EOF when running SMTP is an error */ 551c2aa98e2SPeter Wemm if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 552c2aa98e2SPeter Wemm { 553c2aa98e2SPeter Wemm char *host; 554c2aa98e2SPeter Wemm char *problem; 555c2aa98e2SPeter Wemm 556c2aa98e2SPeter Wemm host = RealHostName; 557c2aa98e2SPeter Wemm if (host == NULL) 558c2aa98e2SPeter Wemm host = "localhost"; 559c2aa98e2SPeter Wemm 560c2aa98e2SPeter Wemm if (feof(fp)) 561c2aa98e2SPeter Wemm problem = "unexpected close"; 562c2aa98e2SPeter Wemm else if (ferror(fp)) 563c2aa98e2SPeter Wemm problem = "I/O error"; 564c2aa98e2SPeter Wemm else 565c2aa98e2SPeter Wemm problem = "read timeout"; 566c2aa98e2SPeter Wemm if (LogLevel > 0 && feof(fp)) 567c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 568c2aa98e2SPeter Wemm "collect: %s on connection from %.100s, sender=%s: %s", 569c2aa98e2SPeter Wemm problem, host, 570c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR), 571c2aa98e2SPeter Wemm errstring(errno)); 572c2aa98e2SPeter Wemm if (feof(fp)) 57306f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 574c2aa98e2SPeter Wemm problem, host, 575c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 576c2aa98e2SPeter Wemm else 57706f25ae9SGregory Neil Shapiro syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 578c2aa98e2SPeter Wemm problem, host, 579c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 580c2aa98e2SPeter Wemm 581c2aa98e2SPeter Wemm /* don't return an error indication */ 582c2aa98e2SPeter Wemm e->e_to = NULL; 583c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 584c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 585c2aa98e2SPeter Wemm 586c2aa98e2SPeter Wemm /* and don't try to deliver the partial message either */ 587c2aa98e2SPeter Wemm if (InChild) 588c2aa98e2SPeter Wemm ExitStat = EX_QUIT; 589065a643dSPeter Wemm finis(TRUE, ExitStat); 59006f25ae9SGregory Neil Shapiro /* NOTREACHED */ 591c2aa98e2SPeter Wemm } 592c2aa98e2SPeter Wemm 593c2aa98e2SPeter Wemm /* 594c2aa98e2SPeter Wemm ** Find out some information from the headers. 595c2aa98e2SPeter Wemm ** Examples are who is the from person & the date. 596c2aa98e2SPeter Wemm */ 597c2aa98e2SPeter Wemm 598c2aa98e2SPeter Wemm eatheader(e, TRUE); 599c2aa98e2SPeter Wemm 600c2aa98e2SPeter Wemm if (GrabTo && e->e_sendqueue == NULL) 601c2aa98e2SPeter Wemm usrerr("No recipient addresses found in header"); 602c2aa98e2SPeter Wemm 603c2aa98e2SPeter Wemm /* collect statistics */ 604c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY) 605c2aa98e2SPeter Wemm markstats(e, (ADDRESS *) NULL, FALSE); 606c2aa98e2SPeter Wemm 607c2aa98e2SPeter Wemm /* 608c2aa98e2SPeter Wemm ** If we have a Return-Receipt-To:, turn it into a DSN. 609c2aa98e2SPeter Wemm */ 610c2aa98e2SPeter Wemm 611c2aa98e2SPeter Wemm if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm ADDRESS *q; 614c2aa98e2SPeter Wemm 615c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 616c2aa98e2SPeter Wemm if (!bitset(QHASNOTIFY, q->q_flags)) 617c2aa98e2SPeter Wemm q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 618c2aa98e2SPeter Wemm } 619c2aa98e2SPeter Wemm 620c2aa98e2SPeter Wemm /* 621c2aa98e2SPeter Wemm ** Add an Apparently-To: line if we have no recipient lines. 622c2aa98e2SPeter Wemm */ 623c2aa98e2SPeter Wemm 624c2aa98e2SPeter Wemm if (hvalue("to", e->e_header) != NULL || 625c2aa98e2SPeter Wemm hvalue("cc", e->e_header) != NULL || 626c2aa98e2SPeter Wemm hvalue("apparently-to", e->e_header) != NULL) 627c2aa98e2SPeter Wemm { 628c2aa98e2SPeter Wemm /* have a valid recipient header -- delete Bcc: headers */ 629c2aa98e2SPeter Wemm e->e_flags |= EF_DELETE_BCC; 630c2aa98e2SPeter Wemm } 631c2aa98e2SPeter Wemm else if (hvalue("bcc", e->e_header) == NULL) 632c2aa98e2SPeter Wemm { 633c2aa98e2SPeter Wemm /* no valid recipient headers */ 634c2aa98e2SPeter Wemm register ADDRESS *q; 635c2aa98e2SPeter Wemm char *hdr = NULL; 636c2aa98e2SPeter Wemm 637c2aa98e2SPeter Wemm /* create an Apparently-To: field */ 638c2aa98e2SPeter Wemm /* that or reject the message.... */ 639c2aa98e2SPeter Wemm switch (NoRecipientAction) 640c2aa98e2SPeter Wemm { 641c2aa98e2SPeter Wemm case NRA_ADD_APPARENTLY_TO: 642c2aa98e2SPeter Wemm hdr = "Apparently-To"; 643c2aa98e2SPeter Wemm break; 644c2aa98e2SPeter Wemm 645c2aa98e2SPeter Wemm case NRA_ADD_TO: 646c2aa98e2SPeter Wemm hdr = "To"; 647c2aa98e2SPeter Wemm break; 648c2aa98e2SPeter Wemm 649c2aa98e2SPeter Wemm case NRA_ADD_BCC: 65006f25ae9SGregory Neil Shapiro addheader("Bcc", " ", 0, &e->e_header); 651c2aa98e2SPeter Wemm break; 652c2aa98e2SPeter Wemm 653c2aa98e2SPeter Wemm case NRA_ADD_TO_UNDISCLOSED: 65406f25ae9SGregory Neil Shapiro addheader("To", "undisclosed-recipients:;", 0, &e->e_header); 655c2aa98e2SPeter Wemm break; 656c2aa98e2SPeter Wemm } 657c2aa98e2SPeter Wemm 658c2aa98e2SPeter Wemm if (hdr != NULL) 659c2aa98e2SPeter Wemm { 660c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 661c2aa98e2SPeter Wemm { 662c2aa98e2SPeter Wemm if (q->q_alias != NULL) 663c2aa98e2SPeter Wemm continue; 664c2aa98e2SPeter Wemm if (tTd(30, 3)) 66506f25ae9SGregory Neil Shapiro dprintf("Adding %s: %s\n", 666c2aa98e2SPeter Wemm hdr, q->q_paddr); 66706f25ae9SGregory Neil Shapiro addheader(hdr, q->q_paddr, 0, &e->e_header); 668c2aa98e2SPeter Wemm } 669c2aa98e2SPeter Wemm } 670c2aa98e2SPeter Wemm } 671c2aa98e2SPeter Wemm 672c2aa98e2SPeter Wemm /* check for message too large */ 67342e5d165SGregory Neil Shapiro if (bitset(EF_TOOBIG, e->e_flags)) 674c2aa98e2SPeter Wemm { 675c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 676c2aa98e2SPeter Wemm e->e_status = "5.2.3"; 67706f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 67806f25ae9SGregory Neil Shapiro "552 Message exceeds maximum fixed size (%ld)", 679c2aa98e2SPeter Wemm MaxMessageSize); 680c2aa98e2SPeter Wemm if (LogLevel > 6) 681c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 682c2aa98e2SPeter Wemm "message size (%ld) exceeds maximum (%ld)", 683c2aa98e2SPeter Wemm e->e_msgsize, MaxMessageSize); 684c2aa98e2SPeter Wemm } 685c2aa98e2SPeter Wemm 686c2aa98e2SPeter Wemm /* check for illegal 8-bit data */ 687c2aa98e2SPeter Wemm if (HasEightBits) 688c2aa98e2SPeter Wemm { 689c2aa98e2SPeter Wemm e->e_flags |= EF_HAS8BIT; 690c2aa98e2SPeter Wemm if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 691c2aa98e2SPeter Wemm !bitset(EF_IS_MIME, e->e_flags)) 692c2aa98e2SPeter Wemm { 693c2aa98e2SPeter Wemm e->e_status = "5.6.1"; 69406f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 695c2aa98e2SPeter Wemm } 696c2aa98e2SPeter Wemm } 697c2aa98e2SPeter Wemm else 698c2aa98e2SPeter Wemm { 699c2aa98e2SPeter Wemm /* if it claimed to be 8 bits, well, it lied.... */ 700c2aa98e2SPeter Wemm if (e->e_bodytype != NULL && 701c2aa98e2SPeter Wemm strcasecmp(e->e_bodytype, "8BITMIME") == 0) 702c2aa98e2SPeter Wemm e->e_bodytype = "7BIT"; 703c2aa98e2SPeter Wemm } 704c2aa98e2SPeter Wemm 70506f25ae9SGregory Neil Shapiro if (SuperSafe) 70606f25ae9SGregory Neil Shapiro { 707c2aa98e2SPeter Wemm if ((e->e_dfp = fopen(dfname, "r")) == NULL) 708c2aa98e2SPeter Wemm { 709c2aa98e2SPeter Wemm /* we haven't acked receipt yet, so just chuck this */ 710c2aa98e2SPeter Wemm syserr("Cannot reopen %s", dfname); 711065a643dSPeter Wemm finis(TRUE, ExitStat); 71206f25ae9SGregory Neil Shapiro /* NOTREACHED */ 713c2aa98e2SPeter Wemm } 714c2aa98e2SPeter Wemm } 71506f25ae9SGregory Neil Shapiro else 71606f25ae9SGregory Neil Shapiro e->e_dfp = df; 71706f25ae9SGregory Neil Shapiro if (e->e_dfp == NULL) 71806f25ae9SGregory Neil Shapiro syserr("!collect: no e_dfp"); 71906f25ae9SGregory Neil Shapiro } 720c2aa98e2SPeter Wemm 721c2aa98e2SPeter Wemm 722c2aa98e2SPeter Wemm static void 723c2aa98e2SPeter Wemm collecttimeout(timeout) 724c2aa98e2SPeter Wemm time_t timeout; 725c2aa98e2SPeter Wemm { 7268774250cSGregory Neil Shapiro int save_errno = errno; 727c2aa98e2SPeter Wemm 7288774250cSGregory Neil Shapiro /* 7298774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 7308774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 7318774250cSGregory Neil Shapiro ** DOING. 7328774250cSGregory Neil Shapiro */ 7338774250cSGregory Neil Shapiro 7348774250cSGregory Neil Shapiro if (CollectProgress) 7358774250cSGregory Neil Shapiro { 7368774250cSGregory Neil Shapiro /* reset the timeout */ 7378774250cSGregory Neil Shapiro CollectTimeout = sigsafe_setevent(timeout, collecttimeout, 7388774250cSGregory Neil Shapiro timeout); 739c2aa98e2SPeter Wemm CollectProgress = FALSE; 740c2aa98e2SPeter Wemm } 7418774250cSGregory Neil Shapiro else 7428774250cSGregory Neil Shapiro { 7438774250cSGregory Neil Shapiro /* event is done */ 7448774250cSGregory Neil Shapiro CollectTimeout = NULL; 7458774250cSGregory Neil Shapiro } 7468774250cSGregory Neil Shapiro 7478774250cSGregory Neil Shapiro /* if no progress was made or problem resetting event, die now */ 7488774250cSGregory Neil Shapiro if (CollectTimeout == NULL) 7498774250cSGregory Neil Shapiro { 7508774250cSGregory Neil Shapiro errno = ETIMEDOUT; 7518774250cSGregory Neil Shapiro longjmp(CtxCollectTimeout, 1); 7528774250cSGregory Neil Shapiro } 7538774250cSGregory Neil Shapiro 7548774250cSGregory Neil Shapiro errno = save_errno; 7558774250cSGregory Neil Shapiro } 7568774250cSGregory Neil Shapiro /* 75706f25ae9SGregory Neil Shapiro ** DFERROR -- signal error on writing the data file. 758c2aa98e2SPeter Wemm ** 759c2aa98e2SPeter Wemm ** Parameters: 76006f25ae9SGregory Neil Shapiro ** df -- the file pointer for the data file. 76106f25ae9SGregory Neil Shapiro ** msg -- detailed message. 762c2aa98e2SPeter Wemm ** e -- the current envelope. 763c2aa98e2SPeter Wemm ** 764c2aa98e2SPeter Wemm ** Returns: 765c2aa98e2SPeter Wemm ** none. 766c2aa98e2SPeter Wemm ** 767c2aa98e2SPeter Wemm ** Side Effects: 768c2aa98e2SPeter Wemm ** Gives an error message. 769c2aa98e2SPeter Wemm ** Arranges for following output to go elsewhere. 770c2aa98e2SPeter Wemm */ 771c2aa98e2SPeter Wemm 77206f25ae9SGregory Neil Shapiro static void 77306f25ae9SGregory Neil Shapiro dferror(df, msg, e) 77406f25ae9SGregory Neil Shapiro FILE *volatile df; 77506f25ae9SGregory Neil Shapiro char *msg; 776c2aa98e2SPeter Wemm register ENVELOPE *e; 777c2aa98e2SPeter Wemm { 77806f25ae9SGregory Neil Shapiro char *dfname; 77906f25ae9SGregory Neil Shapiro 78006f25ae9SGregory Neil Shapiro dfname = queuename(e, 'd'); 781c2aa98e2SPeter Wemm setstat(EX_IOERR); 782c2aa98e2SPeter Wemm if (errno == ENOSPC) 783c2aa98e2SPeter Wemm { 784c2aa98e2SPeter Wemm #if STAT64 > 0 785c2aa98e2SPeter Wemm struct stat64 st; 78606f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 787c2aa98e2SPeter Wemm struct stat st; 78806f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 789c2aa98e2SPeter Wemm long avail; 790c2aa98e2SPeter Wemm long bsize; 791c2aa98e2SPeter Wemm 792c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 793c2aa98e2SPeter Wemm 794c2aa98e2SPeter Wemm if ( 795c2aa98e2SPeter Wemm #if STAT64 > 0 79606f25ae9SGregory Neil Shapiro fstat64(fileno(df), &st) 79706f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 79806f25ae9SGregory Neil Shapiro fstat(fileno(df), &st) 79906f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 800c2aa98e2SPeter Wemm < 0) 801c2aa98e2SPeter Wemm st.st_size = 0; 80206f25ae9SGregory Neil Shapiro (void) freopen(dfname, "w", df); 803c2aa98e2SPeter Wemm if (st.st_size <= 0) 80406f25ae9SGregory Neil Shapiro fprintf(df, "\n*** Mail could not be accepted"); 80506f25ae9SGregory Neil Shapiro /*CONSTCOND*/ 806c2aa98e2SPeter Wemm else if (sizeof st.st_size > sizeof (long)) 80706f25ae9SGregory Neil Shapiro fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n", 808c2aa98e2SPeter Wemm quad_to_string(st.st_size)); 809c2aa98e2SPeter Wemm else 81006f25ae9SGregory Neil Shapiro fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n", 811c2aa98e2SPeter Wemm (unsigned long) st.st_size); 81206f25ae9SGregory Neil Shapiro fprintf(df, "*** at %s due to lack of disk space for temp file.\n", 813c2aa98e2SPeter Wemm MyHostName); 81406f25ae9SGregory Neil Shapiro avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize); 815c2aa98e2SPeter Wemm if (avail > 0) 816c2aa98e2SPeter Wemm { 817c2aa98e2SPeter Wemm if (bsize > 1024) 818c2aa98e2SPeter Wemm avail *= bsize / 1024; 819c2aa98e2SPeter Wemm else if (bsize < 1024) 820c2aa98e2SPeter Wemm avail /= 1024 / bsize; 82106f25ae9SGregory Neil Shapiro fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n", 822c2aa98e2SPeter Wemm avail); 823c2aa98e2SPeter Wemm } 824c2aa98e2SPeter Wemm e->e_status = "4.3.1"; 82506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 826c2aa98e2SPeter Wemm } 827c2aa98e2SPeter Wemm else 82806f25ae9SGregory Neil Shapiro syserr("collect: Cannot write %s (%s, uid=%d)", 82906f25ae9SGregory Neil Shapiro dfname, msg, geteuid()); 83006f25ae9SGregory Neil Shapiro if (freopen("/dev/null", "w", df) == NULL) 831c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 83206f25ae9SGregory Neil Shapiro "dferror: freopen(\"/dev/null\") failed: %s", 833c2aa98e2SPeter Wemm errstring(errno)); 834c2aa98e2SPeter Wemm } 835c2aa98e2SPeter Wemm /* 836c2aa98e2SPeter Wemm ** EATFROM -- chew up a UNIX style from line and process 837c2aa98e2SPeter Wemm ** 838c2aa98e2SPeter Wemm ** This does indeed make some assumptions about the format 839c2aa98e2SPeter Wemm ** of UNIX messages. 840c2aa98e2SPeter Wemm ** 841c2aa98e2SPeter Wemm ** Parameters: 842c2aa98e2SPeter Wemm ** fm -- the from line. 843c2aa98e2SPeter Wemm ** 844c2aa98e2SPeter Wemm ** Returns: 845c2aa98e2SPeter Wemm ** none. 846c2aa98e2SPeter Wemm ** 847c2aa98e2SPeter Wemm ** Side Effects: 848c2aa98e2SPeter Wemm ** extracts what information it can from the header, 849c2aa98e2SPeter Wemm ** such as the date. 850c2aa98e2SPeter Wemm */ 851c2aa98e2SPeter Wemm 852c2aa98e2SPeter Wemm #ifndef NOTUNIX 853c2aa98e2SPeter Wemm 85406f25ae9SGregory Neil Shapiro static char *DowList[] = 855c2aa98e2SPeter Wemm { 856c2aa98e2SPeter Wemm "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 857c2aa98e2SPeter Wemm }; 858c2aa98e2SPeter Wemm 85906f25ae9SGregory Neil Shapiro static char *MonthList[] = 860c2aa98e2SPeter Wemm { 861c2aa98e2SPeter Wemm "Jan", "Feb", "Mar", "Apr", "May", "Jun", 862c2aa98e2SPeter Wemm "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 863c2aa98e2SPeter Wemm NULL 864c2aa98e2SPeter Wemm }; 865c2aa98e2SPeter Wemm 86606f25ae9SGregory Neil Shapiro static void 867c2aa98e2SPeter Wemm eatfrom(fm, e) 868c2aa98e2SPeter Wemm char *volatile fm; 869c2aa98e2SPeter Wemm register ENVELOPE *e; 870c2aa98e2SPeter Wemm { 871c2aa98e2SPeter Wemm register char *p; 872c2aa98e2SPeter Wemm register char **dt; 873c2aa98e2SPeter Wemm 874c2aa98e2SPeter Wemm if (tTd(30, 2)) 87506f25ae9SGregory Neil Shapiro dprintf("eatfrom(%s)\n", fm); 876c2aa98e2SPeter Wemm 877c2aa98e2SPeter Wemm /* find the date part */ 878c2aa98e2SPeter Wemm p = fm; 879c2aa98e2SPeter Wemm while (*p != '\0') 880c2aa98e2SPeter Wemm { 881c2aa98e2SPeter Wemm /* skip a word */ 882c2aa98e2SPeter Wemm while (*p != '\0' && *p != ' ') 883c2aa98e2SPeter Wemm p++; 884c2aa98e2SPeter Wemm while (*p == ' ') 885c2aa98e2SPeter Wemm p++; 886193538b7SGregory Neil Shapiro if (strlen(p) < 17) 887193538b7SGregory Neil Shapiro { 888193538b7SGregory Neil Shapiro /* no room for the date */ 889193538b7SGregory Neil Shapiro return; 890193538b7SGregory Neil Shapiro } 891c2aa98e2SPeter Wemm if (!(isascii(*p) && isupper(*p)) || 892c2aa98e2SPeter Wemm p[3] != ' ' || p[13] != ':' || p[16] != ':') 893c2aa98e2SPeter Wemm continue; 894c2aa98e2SPeter Wemm 895c2aa98e2SPeter Wemm /* we have a possible date */ 896c2aa98e2SPeter Wemm for (dt = DowList; *dt != NULL; dt++) 897c2aa98e2SPeter Wemm if (strncmp(*dt, p, 3) == 0) 898c2aa98e2SPeter Wemm break; 899c2aa98e2SPeter Wemm if (*dt == NULL) 900c2aa98e2SPeter Wemm continue; 901c2aa98e2SPeter Wemm 902c2aa98e2SPeter Wemm for (dt = MonthList; *dt != NULL; dt++) 903193538b7SGregory Neil Shapiro { 904c2aa98e2SPeter Wemm if (strncmp(*dt, &p[4], 3) == 0) 905c2aa98e2SPeter Wemm break; 906193538b7SGregory Neil Shapiro } 907c2aa98e2SPeter Wemm if (*dt != NULL) 908c2aa98e2SPeter Wemm break; 909c2aa98e2SPeter Wemm } 910c2aa98e2SPeter Wemm 911c2aa98e2SPeter Wemm if (*p != '\0') 912c2aa98e2SPeter Wemm { 913c2aa98e2SPeter Wemm char *q; 914c2aa98e2SPeter Wemm 915c2aa98e2SPeter Wemm /* we have found a date */ 916c2aa98e2SPeter Wemm q = xalloc(25); 91706f25ae9SGregory Neil Shapiro (void) strlcpy(q, p, 25); 918c2aa98e2SPeter Wemm q = arpadate(q); 919c2aa98e2SPeter Wemm define('a', newstr(q), e); 920c2aa98e2SPeter Wemm } 921c2aa98e2SPeter Wemm } 92206f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 923