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 15602a2b1bSGregory Neil Shapiro static char id[] = "@(#)$Id: collect.c,v 8.136.4.15 2001/02/21 01:05:59 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; 50c2aa98e2SPeter Wemm static bool CollectProgress; 51c2aa98e2SPeter Wemm static EVENT *CollectTimeout; 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) 21506f25ae9SGregory Neil Shapiro (void) fprintf(TrafficLogFile, "%05d <<< ", 216c2aa98e2SPeter Wemm (int) getpid()); 217c2aa98e2SPeter Wemm if (c == EOF) 21806f25ae9SGregory Neil Shapiro (void) fprintf(TrafficLogFile, "[EOF]\n"); 219c2aa98e2SPeter Wemm else 22006f25ae9SGregory Neil Shapiro (void) putc(c, TrafficLogFile); 221c2aa98e2SPeter Wemm } 222c2aa98e2SPeter Wemm if (c == EOF) 223c2aa98e2SPeter Wemm goto readerr; 224c2aa98e2SPeter Wemm if (SevenBitInput) 225c2aa98e2SPeter Wemm c &= 0x7f; 226c2aa98e2SPeter Wemm else 227c2aa98e2SPeter Wemm HasEightBits |= bitset(0x80, c); 228c2aa98e2SPeter Wemm } 229c2aa98e2SPeter Wemm if (tTd(30, 94)) 23006f25ae9SGregory Neil Shapiro dprintf("istate=%d, c=%c (0x%x)\n", 23106f25ae9SGregory Neil Shapiro istate, (char) c, c); 232c2aa98e2SPeter Wemm switch (istate) 233c2aa98e2SPeter Wemm { 234c2aa98e2SPeter Wemm case IS_BOL: 235c2aa98e2SPeter Wemm if (c == '.') 236c2aa98e2SPeter Wemm { 237c2aa98e2SPeter Wemm istate = IS_DOT; 238c2aa98e2SPeter Wemm continue; 239c2aa98e2SPeter Wemm } 240c2aa98e2SPeter Wemm break; 241c2aa98e2SPeter Wemm 242c2aa98e2SPeter Wemm case IS_DOT: 243c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot && 244c2aa98e2SPeter Wemm !bitset(EF_NL_NOT_EOL, e->e_flags)) 245c2aa98e2SPeter Wemm goto readerr; 246c2aa98e2SPeter Wemm else if (c == '\r' && 247c2aa98e2SPeter Wemm !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 248c2aa98e2SPeter Wemm { 249c2aa98e2SPeter Wemm istate = IS_DOTCR; 250c2aa98e2SPeter Wemm continue; 251c2aa98e2SPeter Wemm } 252c2aa98e2SPeter Wemm else if (c != '.' || 253c2aa98e2SPeter Wemm (OpMode != MD_SMTP && 254c2aa98e2SPeter Wemm OpMode != MD_DAEMON && 255c2aa98e2SPeter Wemm OpMode != MD_ARPAFTP)) 256c2aa98e2SPeter Wemm { 257c2aa98e2SPeter Wemm *pbp++ = c; 258c2aa98e2SPeter Wemm c = '.'; 259c2aa98e2SPeter Wemm } 260c2aa98e2SPeter Wemm break; 261c2aa98e2SPeter Wemm 262c2aa98e2SPeter Wemm case IS_DOTCR: 263c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot) 264c2aa98e2SPeter Wemm goto readerr; 265c2aa98e2SPeter Wemm else 266c2aa98e2SPeter Wemm { 267c2aa98e2SPeter Wemm /* push back the ".\rx" */ 268c2aa98e2SPeter Wemm *pbp++ = c; 269c2aa98e2SPeter Wemm *pbp++ = '\r'; 270c2aa98e2SPeter Wemm c = '.'; 271c2aa98e2SPeter Wemm } 272c2aa98e2SPeter Wemm break; 273c2aa98e2SPeter Wemm 274c2aa98e2SPeter Wemm case IS_CR: 275c2aa98e2SPeter Wemm if (c == '\n') 276c2aa98e2SPeter Wemm istate = IS_BOL; 277c2aa98e2SPeter Wemm else 278c2aa98e2SPeter Wemm { 27906f25ae9SGregory Neil Shapiro (void) ungetc(c, fp); 280c2aa98e2SPeter Wemm c = '\r'; 281c2aa98e2SPeter Wemm istate = IS_NORM; 282c2aa98e2SPeter Wemm } 283c2aa98e2SPeter Wemm goto bufferchar; 284c2aa98e2SPeter Wemm } 285c2aa98e2SPeter Wemm 286c2aa98e2SPeter Wemm if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 287c2aa98e2SPeter Wemm { 288c2aa98e2SPeter Wemm istate = IS_CR; 289c2aa98e2SPeter Wemm continue; 290c2aa98e2SPeter Wemm } 291c2aa98e2SPeter Wemm else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 292c2aa98e2SPeter Wemm istate = IS_BOL; 293c2aa98e2SPeter Wemm else 294c2aa98e2SPeter Wemm istate = IS_NORM; 295c2aa98e2SPeter Wemm 296c2aa98e2SPeter Wemm bufferchar: 297c2aa98e2SPeter Wemm if (!headeronly) 29842e5d165SGregory Neil Shapiro { 29942e5d165SGregory Neil Shapiro /* no overflow? */ 30042e5d165SGregory Neil Shapiro if (e->e_msgsize >= 0) 30142e5d165SGregory Neil Shapiro { 302c2aa98e2SPeter Wemm e->e_msgsize++; 30342e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 && 30442e5d165SGregory Neil Shapiro !bitset(EF_TOOBIG, e->e_flags) && 30542e5d165SGregory Neil Shapiro e->e_msgsize > MaxMessageSize) 30642e5d165SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 30742e5d165SGregory Neil Shapiro } 30842e5d165SGregory Neil Shapiro } 30925bab6e9SPeter Wemm switch (mstate) 310c2aa98e2SPeter Wemm { 31125bab6e9SPeter Wemm case MS_BODY: 312c2aa98e2SPeter Wemm /* just put the character out */ 31342e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 31406f25ae9SGregory Neil Shapiro (void) putc(c, df); 31525bab6e9SPeter Wemm 31606f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 31725bab6e9SPeter Wemm 31825bab6e9SPeter Wemm case MS_DISCARD: 319c2aa98e2SPeter Wemm continue; 320c2aa98e2SPeter Wemm } 321c2aa98e2SPeter Wemm 322c2aa98e2SPeter Wemm /* header -- buffer up */ 323c2aa98e2SPeter Wemm if (bp >= &buf[buflen - 2]) 324c2aa98e2SPeter Wemm { 325c2aa98e2SPeter Wemm char *obuf; 326c2aa98e2SPeter Wemm 327c2aa98e2SPeter Wemm if (mstate != MS_HEADER) 328c2aa98e2SPeter Wemm break; 329c2aa98e2SPeter Wemm 330c2aa98e2SPeter Wemm /* out of space for header */ 331c2aa98e2SPeter Wemm obuf = buf; 332c2aa98e2SPeter Wemm if (buflen < MEMCHUNKSIZE) 333c2aa98e2SPeter Wemm buflen *= 2; 334c2aa98e2SPeter Wemm else 335c2aa98e2SPeter Wemm buflen += MEMCHUNKSIZE; 336c2aa98e2SPeter Wemm buf = xalloc(buflen); 33706f25ae9SGregory Neil Shapiro memmove(buf, obuf, bp - obuf); 338c2aa98e2SPeter Wemm bp = &buf[bp - obuf]; 339c2aa98e2SPeter Wemm if (obuf != bufbuf) 340c2aa98e2SPeter Wemm free(obuf); 341c2aa98e2SPeter Wemm } 342c2aa98e2SPeter Wemm if (c >= 0200 && c <= 0237) 343c2aa98e2SPeter Wemm { 34406f25ae9SGregory Neil Shapiro #if 0 /* causes complaints -- figure out something for 8.11 */ 345c2aa98e2SPeter Wemm usrerr("Illegal character 0x%x in header", c); 34606f25ae9SGregory Neil Shapiro #else /* 0 */ 34706f25ae9SGregory Neil Shapiro /* EMPTY */ 34806f25ae9SGregory Neil Shapiro #endif /* 0 */ 349c2aa98e2SPeter Wemm } 350c2aa98e2SPeter Wemm else if (c != '\0') 35125bab6e9SPeter Wemm { 352c2aa98e2SPeter Wemm *bp++ = c; 353602a2b1bSGregory Neil Shapiro hdrslen++; 3542e43090eSPeter Wemm if (MaxHeadersLength > 0 && 355602a2b1bSGregory Neil Shapiro hdrslen > MaxHeadersLength) 35625bab6e9SPeter Wemm { 35725bab6e9SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 3582e43090eSPeter Wemm "headers too large (%d max) from %s during message collect", 3592e43090eSPeter Wemm MaxHeadersLength, 36025bab6e9SPeter Wemm CurHostName != NULL ? CurHostName : "localhost"); 36125bab6e9SPeter Wemm errno = 0; 36225bab6e9SPeter Wemm e->e_flags |= EF_CLRQUEUE; 36325bab6e9SPeter Wemm e->e_status = "5.6.0"; 36406f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 36506f25ae9SGregory Neil Shapiro "552 Headers too large (%d max)", 3662e43090eSPeter Wemm MaxHeadersLength); 36725bab6e9SPeter Wemm mstate = MS_DISCARD; 36825bab6e9SPeter Wemm } 36925bab6e9SPeter Wemm } 370c2aa98e2SPeter Wemm if (istate == IS_BOL) 371c2aa98e2SPeter Wemm break; 372c2aa98e2SPeter Wemm } 373c2aa98e2SPeter Wemm *bp = '\0'; 374c2aa98e2SPeter Wemm 375c2aa98e2SPeter Wemm nextstate: 376c2aa98e2SPeter Wemm if (tTd(30, 35)) 37706f25ae9SGregory Neil Shapiro dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 378c2aa98e2SPeter Wemm istate, mstate, buf); 379c2aa98e2SPeter Wemm switch (mstate) 380c2aa98e2SPeter Wemm { 381c2aa98e2SPeter Wemm case MS_UFROM: 382c2aa98e2SPeter Wemm mstate = MS_HEADER; 383c2aa98e2SPeter Wemm #ifndef NOTUNIX 384c2aa98e2SPeter Wemm if (strncmp(buf, "From ", 5) == 0) 385c2aa98e2SPeter Wemm { 386c2aa98e2SPeter Wemm bp = buf; 387c2aa98e2SPeter Wemm eatfrom(buf, e); 388c2aa98e2SPeter Wemm continue; 389c2aa98e2SPeter Wemm } 39006f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 39106f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 392c2aa98e2SPeter Wemm 393c2aa98e2SPeter Wemm case MS_HEADER: 394c2aa98e2SPeter Wemm if (!isheader(buf)) 395c2aa98e2SPeter Wemm { 396c2aa98e2SPeter Wemm mstate = MS_BODY; 397c2aa98e2SPeter Wemm goto nextstate; 398c2aa98e2SPeter Wemm } 399c2aa98e2SPeter Wemm 400c2aa98e2SPeter Wemm /* check for possible continuation line */ 401c2aa98e2SPeter Wemm do 402c2aa98e2SPeter Wemm { 403c2aa98e2SPeter Wemm clearerr(fp); 404c2aa98e2SPeter Wemm errno = 0; 405c2aa98e2SPeter Wemm c = getc(fp); 40642e5d165SGregory Neil Shapiro } while (c == EOF && errno == EINTR); 407c2aa98e2SPeter Wemm if (c != EOF) 40806f25ae9SGregory Neil Shapiro (void) ungetc(c, fp); 409c2aa98e2SPeter Wemm if (c == ' ' || c == '\t') 410c2aa98e2SPeter Wemm { 411c2aa98e2SPeter Wemm /* yep -- defer this */ 412c2aa98e2SPeter Wemm continue; 413c2aa98e2SPeter Wemm } 414c2aa98e2SPeter Wemm 415c2aa98e2SPeter Wemm /* trim off trailing CRLF or NL */ 416c2aa98e2SPeter Wemm if (*--bp != '\n' || *--bp != '\r') 417c2aa98e2SPeter Wemm bp++; 418c2aa98e2SPeter Wemm *bp = '\0'; 41925bab6e9SPeter Wemm 42006f25ae9SGregory Neil Shapiro if (bitset(H_EOH, chompheader(buf, 42106f25ae9SGregory Neil Shapiro CHHDR_CHECK | CHHDR_USER, 42206f25ae9SGregory Neil Shapiro hdrp, e))) 423c2aa98e2SPeter Wemm { 424c2aa98e2SPeter Wemm mstate = MS_BODY; 425c2aa98e2SPeter Wemm goto nextstate; 426c2aa98e2SPeter Wemm } 42706f25ae9SGregory Neil Shapiro numhdrs++; 428c2aa98e2SPeter Wemm break; 429c2aa98e2SPeter Wemm 430c2aa98e2SPeter Wemm case MS_BODY: 431c2aa98e2SPeter Wemm if (tTd(30, 1)) 43206f25ae9SGregory Neil Shapiro dprintf("EOH\n"); 43306f25ae9SGregory Neil Shapiro 434c2aa98e2SPeter Wemm if (headeronly) 435c2aa98e2SPeter Wemm goto readerr; 43606f25ae9SGregory Neil Shapiro 43706f25ae9SGregory Neil Shapiro /* call the end-of-header check ruleset */ 43806f25ae9SGregory Neil Shapiro snprintf(hnum, sizeof hnum, "%d", numhdrs); 43906f25ae9SGregory Neil Shapiro snprintf(hsize, sizeof hsize, "%d", hdrslen); 44006f25ae9SGregory Neil Shapiro if (tTd(30, 10)) 44106f25ae9SGregory Neil Shapiro dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 44206f25ae9SGregory Neil Shapiro hnum, hsize); 44306f25ae9SGregory Neil Shapiro rstat = rscheck("check_eoh", hnum, hsize, e, FALSE, 444193538b7SGregory Neil Shapiro TRUE, 4, NULL); 44506f25ae9SGregory Neil Shapiro 446c2aa98e2SPeter Wemm bp = buf; 447c2aa98e2SPeter Wemm 448c2aa98e2SPeter Wemm /* toss blank line */ 449c2aa98e2SPeter Wemm if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 450c2aa98e2SPeter Wemm bp[0] == '\r' && bp[1] == '\n') || 451c2aa98e2SPeter Wemm (!bitset(EF_NL_NOT_EOL, e->e_flags) && 452c2aa98e2SPeter Wemm bp[0] == '\n')) 453c2aa98e2SPeter Wemm { 454c2aa98e2SPeter Wemm break; 455c2aa98e2SPeter Wemm } 456c2aa98e2SPeter Wemm 457c2aa98e2SPeter Wemm /* if not a blank separator, write it out */ 45842e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 459c2aa98e2SPeter Wemm { 460c2aa98e2SPeter Wemm while (*bp != '\0') 46106f25ae9SGregory Neil Shapiro (void) putc(*bp++, df); 462c2aa98e2SPeter Wemm } 463c2aa98e2SPeter Wemm break; 464c2aa98e2SPeter Wemm } 465c2aa98e2SPeter Wemm bp = buf; 466c2aa98e2SPeter Wemm } 467c2aa98e2SPeter Wemm 468c2aa98e2SPeter Wemm readerr: 469c2aa98e2SPeter Wemm if ((feof(fp) && smtpmode) || ferror(fp)) 470c2aa98e2SPeter Wemm { 471c2aa98e2SPeter Wemm const char *errmsg = errstring(errno); 472c2aa98e2SPeter Wemm 473c2aa98e2SPeter Wemm if (tTd(30, 1)) 47406f25ae9SGregory Neil Shapiro dprintf("collect: premature EOM: %s\n", errmsg); 475c2aa98e2SPeter Wemm if (LogLevel >= 2) 476c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 477c2aa98e2SPeter Wemm "collect: premature EOM: %s", errmsg); 478c2aa98e2SPeter Wemm inputerr = TRUE; 479c2aa98e2SPeter Wemm } 480c2aa98e2SPeter Wemm 481c2aa98e2SPeter Wemm /* reset global timer */ 482c2aa98e2SPeter Wemm clrevent(CollectTimeout); 483c2aa98e2SPeter Wemm 484c2aa98e2SPeter Wemm if (headeronly) 485c2aa98e2SPeter Wemm return; 486c2aa98e2SPeter Wemm 48706f25ae9SGregory Neil Shapiro if (df == NULL) 488c2aa98e2SPeter Wemm { 48906f25ae9SGregory Neil Shapiro /* skip next few clauses */ 49006f25ae9SGregory Neil Shapiro /* EMPTY */ 49106f25ae9SGregory Neil Shapiro } 49206f25ae9SGregory Neil Shapiro else if (fflush(df) != 0 || ferror(df)) 49306f25ae9SGregory Neil Shapiro { 49406f25ae9SGregory Neil Shapiro dferror(df, "fflush||ferror", e); 495c2aa98e2SPeter Wemm flush_errors(TRUE); 496065a643dSPeter Wemm finis(TRUE, ExitStat); 49706f25ae9SGregory Neil Shapiro /* NOTREACHED */ 49806f25ae9SGregory Neil Shapiro } 49906f25ae9SGregory Neil Shapiro else if (!SuperSafe) 50006f25ae9SGregory Neil Shapiro { 50106f25ae9SGregory Neil Shapiro /* skip next few clauses */ 50206f25ae9SGregory Neil Shapiro /* EMPTY */ 50306f25ae9SGregory Neil Shapiro } 50406f25ae9SGregory Neil Shapiro else if (bfcommit(df) < 0) 50506f25ae9SGregory Neil Shapiro { 50606f25ae9SGregory Neil Shapiro int save_errno = errno; 50706f25ae9SGregory Neil Shapiro 50806f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 50906f25ae9SGregory Neil Shapiro { 51006f25ae9SGregory Neil Shapiro char *dfile; 51106f25ae9SGregory Neil Shapiro struct stat st; 51206f25ae9SGregory Neil Shapiro 51306f25ae9SGregory Neil Shapiro dfile = queuename(e, 'd'); 51406f25ae9SGregory Neil Shapiro if (stat(dfile, &st) < 0) 51506f25ae9SGregory Neil Shapiro st.st_size = -1; 51606f25ae9SGregory Neil Shapiro errno = EEXIST; 51706f25ae9SGregory Neil Shapiro syserr("collect: bfcommit(%s): already on disk, size = %ld", 51842e5d165SGregory Neil Shapiro dfile, (long) st.st_size); 51906f25ae9SGregory Neil Shapiro dfd = fileno(df); 52006f25ae9SGregory Neil Shapiro if (dfd >= 0) 52106f25ae9SGregory Neil Shapiro dumpfd(dfd, TRUE, TRUE); 52206f25ae9SGregory Neil Shapiro } 52306f25ae9SGregory Neil Shapiro errno = save_errno; 52406f25ae9SGregory Neil Shapiro dferror(df, "bfcommit", e); 52506f25ae9SGregory Neil Shapiro flush_errors(TRUE); 52606f25ae9SGregory Neil Shapiro finis(save_errno != EEXIST, ExitStat); 52706f25ae9SGregory Neil Shapiro } 528602a2b1bSGregory Neil Shapiro else if (bffsync(df) < 0) 529602a2b1bSGregory Neil Shapiro { 530602a2b1bSGregory Neil Shapiro dferror(df, "bffsync", e); 531602a2b1bSGregory Neil Shapiro flush_errors(TRUE); 532602a2b1bSGregory Neil Shapiro finis(TRUE, ExitStat); 533602a2b1bSGregory Neil Shapiro /* NOTREACHED */ 534602a2b1bSGregory Neil Shapiro } 53506f25ae9SGregory Neil Shapiro else if (bfclose(df) < 0) 53606f25ae9SGregory Neil Shapiro { 53706f25ae9SGregory Neil Shapiro dferror(df, "bfclose", e); 53806f25ae9SGregory Neil Shapiro flush_errors(TRUE); 53906f25ae9SGregory Neil Shapiro finis(TRUE, ExitStat); 54006f25ae9SGregory Neil Shapiro /* NOTREACHED */ 54106f25ae9SGregory Neil Shapiro } 54206f25ae9SGregory Neil Shapiro else 54306f25ae9SGregory Neil Shapiro { 54406f25ae9SGregory Neil Shapiro /* everything is happily flushed to disk */ 54506f25ae9SGregory Neil Shapiro df = NULL; 546c2aa98e2SPeter Wemm } 547c2aa98e2SPeter Wemm 548c2aa98e2SPeter Wemm /* An EOF when running SMTP is an error */ 549c2aa98e2SPeter Wemm if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 550c2aa98e2SPeter Wemm { 551c2aa98e2SPeter Wemm char *host; 552c2aa98e2SPeter Wemm char *problem; 553c2aa98e2SPeter Wemm 554c2aa98e2SPeter Wemm host = RealHostName; 555c2aa98e2SPeter Wemm if (host == NULL) 556c2aa98e2SPeter Wemm host = "localhost"; 557c2aa98e2SPeter Wemm 558c2aa98e2SPeter Wemm if (feof(fp)) 559c2aa98e2SPeter Wemm problem = "unexpected close"; 560c2aa98e2SPeter Wemm else if (ferror(fp)) 561c2aa98e2SPeter Wemm problem = "I/O error"; 562c2aa98e2SPeter Wemm else 563c2aa98e2SPeter Wemm problem = "read timeout"; 564c2aa98e2SPeter Wemm if (LogLevel > 0 && feof(fp)) 565c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 566c2aa98e2SPeter Wemm "collect: %s on connection from %.100s, sender=%s: %s", 567c2aa98e2SPeter Wemm problem, host, 568c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR), 569c2aa98e2SPeter Wemm errstring(errno)); 570c2aa98e2SPeter Wemm if (feof(fp)) 57106f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 572c2aa98e2SPeter Wemm problem, host, 573c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 574c2aa98e2SPeter Wemm else 57506f25ae9SGregory Neil Shapiro syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 576c2aa98e2SPeter Wemm problem, host, 577c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 578c2aa98e2SPeter Wemm 579c2aa98e2SPeter Wemm /* don't return an error indication */ 580c2aa98e2SPeter Wemm e->e_to = NULL; 581c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 582c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 583c2aa98e2SPeter Wemm 584c2aa98e2SPeter Wemm /* and don't try to deliver the partial message either */ 585c2aa98e2SPeter Wemm if (InChild) 586c2aa98e2SPeter Wemm ExitStat = EX_QUIT; 587065a643dSPeter Wemm finis(TRUE, ExitStat); 58806f25ae9SGregory Neil Shapiro /* NOTREACHED */ 589c2aa98e2SPeter Wemm } 590c2aa98e2SPeter Wemm 591c2aa98e2SPeter Wemm /* 592c2aa98e2SPeter Wemm ** Find out some information from the headers. 593c2aa98e2SPeter Wemm ** Examples are who is the from person & the date. 594c2aa98e2SPeter Wemm */ 595c2aa98e2SPeter Wemm 596c2aa98e2SPeter Wemm eatheader(e, TRUE); 597c2aa98e2SPeter Wemm 598c2aa98e2SPeter Wemm if (GrabTo && e->e_sendqueue == NULL) 599c2aa98e2SPeter Wemm usrerr("No recipient addresses found in header"); 600c2aa98e2SPeter Wemm 601c2aa98e2SPeter Wemm /* collect statistics */ 602c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY) 603c2aa98e2SPeter Wemm markstats(e, (ADDRESS *) NULL, FALSE); 604c2aa98e2SPeter Wemm 605c2aa98e2SPeter Wemm /* 606c2aa98e2SPeter Wemm ** If we have a Return-Receipt-To:, turn it into a DSN. 607c2aa98e2SPeter Wemm */ 608c2aa98e2SPeter Wemm 609c2aa98e2SPeter Wemm if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 610c2aa98e2SPeter Wemm { 611c2aa98e2SPeter Wemm ADDRESS *q; 612c2aa98e2SPeter Wemm 613c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 614c2aa98e2SPeter Wemm if (!bitset(QHASNOTIFY, q->q_flags)) 615c2aa98e2SPeter Wemm q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 616c2aa98e2SPeter Wemm } 617c2aa98e2SPeter Wemm 618c2aa98e2SPeter Wemm /* 619c2aa98e2SPeter Wemm ** Add an Apparently-To: line if we have no recipient lines. 620c2aa98e2SPeter Wemm */ 621c2aa98e2SPeter Wemm 622c2aa98e2SPeter Wemm if (hvalue("to", e->e_header) != NULL || 623c2aa98e2SPeter Wemm hvalue("cc", e->e_header) != NULL || 624c2aa98e2SPeter Wemm hvalue("apparently-to", e->e_header) != NULL) 625c2aa98e2SPeter Wemm { 626c2aa98e2SPeter Wemm /* have a valid recipient header -- delete Bcc: headers */ 627c2aa98e2SPeter Wemm e->e_flags |= EF_DELETE_BCC; 628c2aa98e2SPeter Wemm } 629c2aa98e2SPeter Wemm else if (hvalue("bcc", e->e_header) == NULL) 630c2aa98e2SPeter Wemm { 631c2aa98e2SPeter Wemm /* no valid recipient headers */ 632c2aa98e2SPeter Wemm register ADDRESS *q; 633c2aa98e2SPeter Wemm char *hdr = NULL; 634c2aa98e2SPeter Wemm 635c2aa98e2SPeter Wemm /* create an Apparently-To: field */ 636c2aa98e2SPeter Wemm /* that or reject the message.... */ 637c2aa98e2SPeter Wemm switch (NoRecipientAction) 638c2aa98e2SPeter Wemm { 639c2aa98e2SPeter Wemm case NRA_ADD_APPARENTLY_TO: 640c2aa98e2SPeter Wemm hdr = "Apparently-To"; 641c2aa98e2SPeter Wemm break; 642c2aa98e2SPeter Wemm 643c2aa98e2SPeter Wemm case NRA_ADD_TO: 644c2aa98e2SPeter Wemm hdr = "To"; 645c2aa98e2SPeter Wemm break; 646c2aa98e2SPeter Wemm 647c2aa98e2SPeter Wemm case NRA_ADD_BCC: 64806f25ae9SGregory Neil Shapiro addheader("Bcc", " ", 0, &e->e_header); 649c2aa98e2SPeter Wemm break; 650c2aa98e2SPeter Wemm 651c2aa98e2SPeter Wemm case NRA_ADD_TO_UNDISCLOSED: 65206f25ae9SGregory Neil Shapiro addheader("To", "undisclosed-recipients:;", 0, &e->e_header); 653c2aa98e2SPeter Wemm break; 654c2aa98e2SPeter Wemm } 655c2aa98e2SPeter Wemm 656c2aa98e2SPeter Wemm if (hdr != NULL) 657c2aa98e2SPeter Wemm { 658c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 659c2aa98e2SPeter Wemm { 660c2aa98e2SPeter Wemm if (q->q_alias != NULL) 661c2aa98e2SPeter Wemm continue; 662c2aa98e2SPeter Wemm if (tTd(30, 3)) 66306f25ae9SGregory Neil Shapiro dprintf("Adding %s: %s\n", 664c2aa98e2SPeter Wemm hdr, q->q_paddr); 66506f25ae9SGregory Neil Shapiro addheader(hdr, q->q_paddr, 0, &e->e_header); 666c2aa98e2SPeter Wemm } 667c2aa98e2SPeter Wemm } 668c2aa98e2SPeter Wemm } 669c2aa98e2SPeter Wemm 670c2aa98e2SPeter Wemm /* check for message too large */ 67142e5d165SGregory Neil Shapiro if (bitset(EF_TOOBIG, e->e_flags)) 672c2aa98e2SPeter Wemm { 673c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 674c2aa98e2SPeter Wemm e->e_status = "5.2.3"; 67506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 67606f25ae9SGregory Neil Shapiro "552 Message exceeds maximum fixed size (%ld)", 677c2aa98e2SPeter Wemm MaxMessageSize); 678c2aa98e2SPeter Wemm if (LogLevel > 6) 679c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 680c2aa98e2SPeter Wemm "message size (%ld) exceeds maximum (%ld)", 681c2aa98e2SPeter Wemm e->e_msgsize, MaxMessageSize); 682c2aa98e2SPeter Wemm } 683c2aa98e2SPeter Wemm 684c2aa98e2SPeter Wemm /* check for illegal 8-bit data */ 685c2aa98e2SPeter Wemm if (HasEightBits) 686c2aa98e2SPeter Wemm { 687c2aa98e2SPeter Wemm e->e_flags |= EF_HAS8BIT; 688c2aa98e2SPeter Wemm if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 689c2aa98e2SPeter Wemm !bitset(EF_IS_MIME, e->e_flags)) 690c2aa98e2SPeter Wemm { 691c2aa98e2SPeter Wemm e->e_status = "5.6.1"; 69206f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 693c2aa98e2SPeter Wemm } 694c2aa98e2SPeter Wemm } 695c2aa98e2SPeter Wemm else 696c2aa98e2SPeter Wemm { 697c2aa98e2SPeter Wemm /* if it claimed to be 8 bits, well, it lied.... */ 698c2aa98e2SPeter Wemm if (e->e_bodytype != NULL && 699c2aa98e2SPeter Wemm strcasecmp(e->e_bodytype, "8BITMIME") == 0) 700c2aa98e2SPeter Wemm e->e_bodytype = "7BIT"; 701c2aa98e2SPeter Wemm } 702c2aa98e2SPeter Wemm 70306f25ae9SGregory Neil Shapiro if (SuperSafe) 70406f25ae9SGregory Neil Shapiro { 705c2aa98e2SPeter Wemm if ((e->e_dfp = fopen(dfname, "r")) == NULL) 706c2aa98e2SPeter Wemm { 707c2aa98e2SPeter Wemm /* we haven't acked receipt yet, so just chuck this */ 708c2aa98e2SPeter Wemm syserr("Cannot reopen %s", dfname); 709065a643dSPeter Wemm finis(TRUE, ExitStat); 71006f25ae9SGregory Neil Shapiro /* NOTREACHED */ 711c2aa98e2SPeter Wemm } 712c2aa98e2SPeter Wemm } 71306f25ae9SGregory Neil Shapiro else 71406f25ae9SGregory Neil Shapiro e->e_dfp = df; 71506f25ae9SGregory Neil Shapiro if (e->e_dfp == NULL) 71606f25ae9SGregory Neil Shapiro syserr("!collect: no e_dfp"); 71706f25ae9SGregory Neil Shapiro } 718c2aa98e2SPeter Wemm 719c2aa98e2SPeter Wemm 720c2aa98e2SPeter Wemm static void 721c2aa98e2SPeter Wemm collecttimeout(timeout) 722c2aa98e2SPeter Wemm time_t timeout; 723c2aa98e2SPeter Wemm { 724c2aa98e2SPeter Wemm /* if no progress was made, die now */ 725c2aa98e2SPeter Wemm if (!CollectProgress) 726c2aa98e2SPeter Wemm longjmp(CtxCollectTimeout, 1); 727c2aa98e2SPeter Wemm 728c2aa98e2SPeter Wemm /* otherwise reset the timeout */ 729c2aa98e2SPeter Wemm CollectTimeout = setevent(timeout, collecttimeout, timeout); 730c2aa98e2SPeter Wemm CollectProgress = FALSE; 731c2aa98e2SPeter Wemm } 73206f25ae9SGregory Neil Shapiro /* 73306f25ae9SGregory Neil Shapiro ** DFERROR -- signal error on writing the data file. 734c2aa98e2SPeter Wemm ** 735c2aa98e2SPeter Wemm ** Parameters: 73606f25ae9SGregory Neil Shapiro ** df -- the file pointer for the data file. 73706f25ae9SGregory Neil Shapiro ** msg -- detailed message. 738c2aa98e2SPeter Wemm ** e -- the current envelope. 739c2aa98e2SPeter Wemm ** 740c2aa98e2SPeter Wemm ** Returns: 741c2aa98e2SPeter Wemm ** none. 742c2aa98e2SPeter Wemm ** 743c2aa98e2SPeter Wemm ** Side Effects: 744c2aa98e2SPeter Wemm ** Gives an error message. 745c2aa98e2SPeter Wemm ** Arranges for following output to go elsewhere. 746c2aa98e2SPeter Wemm */ 747c2aa98e2SPeter Wemm 74806f25ae9SGregory Neil Shapiro static void 74906f25ae9SGregory Neil Shapiro dferror(df, msg, e) 75006f25ae9SGregory Neil Shapiro FILE *volatile df; 75106f25ae9SGregory Neil Shapiro char *msg; 752c2aa98e2SPeter Wemm register ENVELOPE *e; 753c2aa98e2SPeter Wemm { 75406f25ae9SGregory Neil Shapiro char *dfname; 75506f25ae9SGregory Neil Shapiro 75606f25ae9SGregory Neil Shapiro dfname = queuename(e, 'd'); 757c2aa98e2SPeter Wemm setstat(EX_IOERR); 758c2aa98e2SPeter Wemm if (errno == ENOSPC) 759c2aa98e2SPeter Wemm { 760c2aa98e2SPeter Wemm #if STAT64 > 0 761c2aa98e2SPeter Wemm struct stat64 st; 76206f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 763c2aa98e2SPeter Wemm struct stat st; 76406f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 765c2aa98e2SPeter Wemm long avail; 766c2aa98e2SPeter Wemm long bsize; 767c2aa98e2SPeter Wemm 768c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 769c2aa98e2SPeter Wemm 770c2aa98e2SPeter Wemm if ( 771c2aa98e2SPeter Wemm #if STAT64 > 0 77206f25ae9SGregory Neil Shapiro fstat64(fileno(df), &st) 77306f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 77406f25ae9SGregory Neil Shapiro fstat(fileno(df), &st) 77506f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 776c2aa98e2SPeter Wemm < 0) 777c2aa98e2SPeter Wemm st.st_size = 0; 77806f25ae9SGregory Neil Shapiro (void) freopen(dfname, "w", df); 779c2aa98e2SPeter Wemm if (st.st_size <= 0) 78006f25ae9SGregory Neil Shapiro fprintf(df, "\n*** Mail could not be accepted"); 78106f25ae9SGregory Neil Shapiro /*CONSTCOND*/ 782c2aa98e2SPeter Wemm else if (sizeof st.st_size > sizeof (long)) 78306f25ae9SGregory Neil Shapiro fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n", 784c2aa98e2SPeter Wemm quad_to_string(st.st_size)); 785c2aa98e2SPeter Wemm else 78606f25ae9SGregory Neil Shapiro fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n", 787c2aa98e2SPeter Wemm (unsigned long) st.st_size); 78806f25ae9SGregory Neil Shapiro fprintf(df, "*** at %s due to lack of disk space for temp file.\n", 789c2aa98e2SPeter Wemm MyHostName); 79006f25ae9SGregory Neil Shapiro avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize); 791c2aa98e2SPeter Wemm if (avail > 0) 792c2aa98e2SPeter Wemm { 793c2aa98e2SPeter Wemm if (bsize > 1024) 794c2aa98e2SPeter Wemm avail *= bsize / 1024; 795c2aa98e2SPeter Wemm else if (bsize < 1024) 796c2aa98e2SPeter Wemm avail /= 1024 / bsize; 79706f25ae9SGregory Neil Shapiro fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n", 798c2aa98e2SPeter Wemm avail); 799c2aa98e2SPeter Wemm } 800c2aa98e2SPeter Wemm e->e_status = "4.3.1"; 80106f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 802c2aa98e2SPeter Wemm } 803c2aa98e2SPeter Wemm else 80406f25ae9SGregory Neil Shapiro syserr("collect: Cannot write %s (%s, uid=%d)", 80506f25ae9SGregory Neil Shapiro dfname, msg, geteuid()); 80606f25ae9SGregory Neil Shapiro if (freopen("/dev/null", "w", df) == NULL) 807c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 80806f25ae9SGregory Neil Shapiro "dferror: freopen(\"/dev/null\") failed: %s", 809c2aa98e2SPeter Wemm errstring(errno)); 810c2aa98e2SPeter Wemm } 811c2aa98e2SPeter Wemm /* 812c2aa98e2SPeter Wemm ** EATFROM -- chew up a UNIX style from line and process 813c2aa98e2SPeter Wemm ** 814c2aa98e2SPeter Wemm ** This does indeed make some assumptions about the format 815c2aa98e2SPeter Wemm ** of UNIX messages. 816c2aa98e2SPeter Wemm ** 817c2aa98e2SPeter Wemm ** Parameters: 818c2aa98e2SPeter Wemm ** fm -- the from line. 819c2aa98e2SPeter Wemm ** 820c2aa98e2SPeter Wemm ** Returns: 821c2aa98e2SPeter Wemm ** none. 822c2aa98e2SPeter Wemm ** 823c2aa98e2SPeter Wemm ** Side Effects: 824c2aa98e2SPeter Wemm ** extracts what information it can from the header, 825c2aa98e2SPeter Wemm ** such as the date. 826c2aa98e2SPeter Wemm */ 827c2aa98e2SPeter Wemm 828c2aa98e2SPeter Wemm #ifndef NOTUNIX 829c2aa98e2SPeter Wemm 83006f25ae9SGregory Neil Shapiro static char *DowList[] = 831c2aa98e2SPeter Wemm { 832c2aa98e2SPeter Wemm "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 833c2aa98e2SPeter Wemm }; 834c2aa98e2SPeter Wemm 83506f25ae9SGregory Neil Shapiro static char *MonthList[] = 836c2aa98e2SPeter Wemm { 837c2aa98e2SPeter Wemm "Jan", "Feb", "Mar", "Apr", "May", "Jun", 838c2aa98e2SPeter Wemm "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 839c2aa98e2SPeter Wemm NULL 840c2aa98e2SPeter Wemm }; 841c2aa98e2SPeter Wemm 84206f25ae9SGregory Neil Shapiro static void 843c2aa98e2SPeter Wemm eatfrom(fm, e) 844c2aa98e2SPeter Wemm char *volatile fm; 845c2aa98e2SPeter Wemm register ENVELOPE *e; 846c2aa98e2SPeter Wemm { 847c2aa98e2SPeter Wemm register char *p; 848c2aa98e2SPeter Wemm register char **dt; 849c2aa98e2SPeter Wemm 850c2aa98e2SPeter Wemm if (tTd(30, 2)) 85106f25ae9SGregory Neil Shapiro dprintf("eatfrom(%s)\n", fm); 852c2aa98e2SPeter Wemm 853c2aa98e2SPeter Wemm /* find the date part */ 854c2aa98e2SPeter Wemm p = fm; 855c2aa98e2SPeter Wemm while (*p != '\0') 856c2aa98e2SPeter Wemm { 857c2aa98e2SPeter Wemm /* skip a word */ 858c2aa98e2SPeter Wemm while (*p != '\0' && *p != ' ') 859c2aa98e2SPeter Wemm p++; 860c2aa98e2SPeter Wemm while (*p == ' ') 861c2aa98e2SPeter Wemm p++; 862193538b7SGregory Neil Shapiro if (strlen(p) < 17) 863193538b7SGregory Neil Shapiro { 864193538b7SGregory Neil Shapiro /* no room for the date */ 865193538b7SGregory Neil Shapiro return; 866193538b7SGregory Neil Shapiro } 867c2aa98e2SPeter Wemm if (!(isascii(*p) && isupper(*p)) || 868c2aa98e2SPeter Wemm p[3] != ' ' || p[13] != ':' || p[16] != ':') 869c2aa98e2SPeter Wemm continue; 870c2aa98e2SPeter Wemm 871c2aa98e2SPeter Wemm /* we have a possible date */ 872c2aa98e2SPeter Wemm for (dt = DowList; *dt != NULL; dt++) 873c2aa98e2SPeter Wemm if (strncmp(*dt, p, 3) == 0) 874c2aa98e2SPeter Wemm break; 875c2aa98e2SPeter Wemm if (*dt == NULL) 876c2aa98e2SPeter Wemm continue; 877c2aa98e2SPeter Wemm 878c2aa98e2SPeter Wemm for (dt = MonthList; *dt != NULL; dt++) 879193538b7SGregory Neil Shapiro { 880c2aa98e2SPeter Wemm if (strncmp(*dt, &p[4], 3) == 0) 881c2aa98e2SPeter Wemm break; 882193538b7SGregory Neil Shapiro } 883c2aa98e2SPeter Wemm if (*dt != NULL) 884c2aa98e2SPeter Wemm break; 885c2aa98e2SPeter Wemm } 886c2aa98e2SPeter Wemm 887c2aa98e2SPeter Wemm if (*p != '\0') 888c2aa98e2SPeter Wemm { 889c2aa98e2SPeter Wemm char *q; 890c2aa98e2SPeter Wemm 891c2aa98e2SPeter Wemm /* we have found a date */ 892c2aa98e2SPeter Wemm q = xalloc(25); 89306f25ae9SGregory Neil Shapiro (void) strlcpy(q, p, 25); 894c2aa98e2SPeter Wemm q = arpadate(q); 895c2aa98e2SPeter Wemm define('a', newstr(q), e); 896c2aa98e2SPeter Wemm } 897c2aa98e2SPeter Wemm } 89806f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 899