138032Speter/* 2261194Sgshapiro * Copyright (c) 1998-2006, 2008 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1538032Speter 16266527SgshapiroSM_RCSID("@(#)$Id: collect.c,v 8.287 2013-11-22 20:51:55 ca Exp $") 1764562Sgshapiro 1864562Sgshapirostatic void eatfrom __P((char *volatile, ENVELOPE *)); 1990792Sgshapirostatic void collect_doheader __P((ENVELOPE *)); 2090792Sgshapirostatic SM_FILE_T *collect_dfopen __P((ENVELOPE *)); 2190792Sgshapirostatic SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int)); 2264562Sgshapiro 2390792Sgshapiro/* 2490792Sgshapiro** COLLECT_EOH -- end-of-header processing in collect() 2590792Sgshapiro** 2690792Sgshapiro** Called by collect() when it encounters the blank line 2790792Sgshapiro** separating the header from the message body, or when it 2890792Sgshapiro** encounters EOF in a message that contains only a header. 2990792Sgshapiro** 3090792Sgshapiro** Parameters: 3190792Sgshapiro** e -- envelope 3290792Sgshapiro** numhdrs -- number of headers 3390792Sgshapiro** hdrslen -- length of headers 3490792Sgshapiro** 3590792Sgshapiro** Results: 3690792Sgshapiro** NULL, or handle to open data file 3790792Sgshapiro** 3890792Sgshapiro** Side Effects: 3990792Sgshapiro** end-of-header check ruleset is invoked. 4090792Sgshapiro** envelope state is updated. 4190792Sgshapiro** headers may be added and deleted. 4290792Sgshapiro** selects the queue. 4390792Sgshapiro** opens the data file. 4490792Sgshapiro*/ 4590792Sgshapiro 4690792Sgshapirostatic SM_FILE_T * 4790792Sgshapirocollect_eoh(e, numhdrs, hdrslen) 4890792Sgshapiro ENVELOPE *e; 4990792Sgshapiro int numhdrs; 5090792Sgshapiro int hdrslen; 5190792Sgshapiro{ 5290792Sgshapiro char hnum[16]; 5390792Sgshapiro char hsize[16]; 5490792Sgshapiro 5590792Sgshapiro /* call the end-of-header check ruleset */ 56168515Sgshapiro (void) sm_snprintf(hnum, sizeof(hnum), "%d", numhdrs); 57168515Sgshapiro (void) sm_snprintf(hsize, sizeof(hsize), "%d", hdrslen); 5890792Sgshapiro if (tTd(30, 10)) 5990792Sgshapiro sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 6090792Sgshapiro hnum, hsize); 61102528Sgshapiro (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT, 62285229Sgshapiro 3, NULL, e->e_id, NULL, NULL); 6390792Sgshapiro 6490792Sgshapiro /* 6590792Sgshapiro ** Process the header, 6690792Sgshapiro ** select the queue, open the data file. 6790792Sgshapiro */ 6890792Sgshapiro 6990792Sgshapiro collect_doheader(e); 7090792Sgshapiro return collect_dfopen(e); 7190792Sgshapiro} 7290792Sgshapiro 7390792Sgshapiro/* 7490792Sgshapiro** COLLECT_DOHEADER -- process header in collect() 7590792Sgshapiro** 7690792Sgshapiro** Called by collect() after it has finished parsing the header, 7790792Sgshapiro** but before it selects the queue and creates the data file. 7890792Sgshapiro** The results of processing the header will affect queue selection. 7990792Sgshapiro** 8090792Sgshapiro** Parameters: 8190792Sgshapiro** e -- envelope 8290792Sgshapiro** 8390792Sgshapiro** Results: 8490792Sgshapiro** none. 8590792Sgshapiro** 8690792Sgshapiro** Side Effects: 8790792Sgshapiro** envelope state is updated. 8890792Sgshapiro** headers may be added and deleted. 8990792Sgshapiro*/ 9090792Sgshapiro 9190792Sgshapirostatic void 9290792Sgshapirocollect_doheader(e) 9390792Sgshapiro ENVELOPE *e; 9490792Sgshapiro{ 9590792Sgshapiro /* 9690792Sgshapiro ** Find out some information from the headers. 9790792Sgshapiro ** Examples are who is the from person & the date. 9890792Sgshapiro */ 9990792Sgshapiro 10090792Sgshapiro eatheader(e, true, false); 10190792Sgshapiro 10290792Sgshapiro if (GrabTo && e->e_sendqueue == NULL) 10390792Sgshapiro usrerr("No recipient addresses found in header"); 10490792Sgshapiro 10590792Sgshapiro /* 10690792Sgshapiro ** If we have a Return-Receipt-To:, turn it into a DSN. 10790792Sgshapiro */ 10890792Sgshapiro 10990792Sgshapiro if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 11090792Sgshapiro { 11190792Sgshapiro ADDRESS *q; 11290792Sgshapiro 11390792Sgshapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 11490792Sgshapiro if (!bitset(QHASNOTIFY, q->q_flags)) 11590792Sgshapiro q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 11690792Sgshapiro } 11790792Sgshapiro 11890792Sgshapiro /* 11990792Sgshapiro ** Add an appropriate recipient line if we have none. 12090792Sgshapiro */ 12190792Sgshapiro 12290792Sgshapiro if (hvalue("to", e->e_header) != NULL || 12390792Sgshapiro hvalue("cc", e->e_header) != NULL || 12490792Sgshapiro hvalue("apparently-to", e->e_header) != NULL) 12590792Sgshapiro { 12690792Sgshapiro /* have a valid recipient header -- delete Bcc: headers */ 12790792Sgshapiro e->e_flags |= EF_DELETE_BCC; 12890792Sgshapiro } 12990792Sgshapiro else if (hvalue("bcc", e->e_header) == NULL) 13090792Sgshapiro { 13190792Sgshapiro /* no valid recipient headers */ 13290792Sgshapiro register ADDRESS *q; 13390792Sgshapiro char *hdr = NULL; 13490792Sgshapiro 13590792Sgshapiro /* create a recipient field */ 13690792Sgshapiro switch (NoRecipientAction) 13790792Sgshapiro { 13890792Sgshapiro case NRA_ADD_APPARENTLY_TO: 13990792Sgshapiro hdr = "Apparently-To"; 14090792Sgshapiro break; 14190792Sgshapiro 14290792Sgshapiro case NRA_ADD_TO: 14390792Sgshapiro hdr = "To"; 14490792Sgshapiro break; 14590792Sgshapiro 14690792Sgshapiro case NRA_ADD_BCC: 147168515Sgshapiro addheader("Bcc", " ", 0, e, true); 14890792Sgshapiro break; 14990792Sgshapiro 15090792Sgshapiro case NRA_ADD_TO_UNDISCLOSED: 151168515Sgshapiro addheader("To", "undisclosed-recipients:;", 0, e, true); 15290792Sgshapiro break; 15390792Sgshapiro } 15490792Sgshapiro 15590792Sgshapiro if (hdr != NULL) 15690792Sgshapiro { 15790792Sgshapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15890792Sgshapiro { 15990792Sgshapiro if (q->q_alias != NULL) 16090792Sgshapiro continue; 16190792Sgshapiro if (tTd(30, 3)) 16290792Sgshapiro sm_dprintf("Adding %s: %s\n", 16390792Sgshapiro hdr, q->q_paddr); 164168515Sgshapiro addheader(hdr, q->q_paddr, 0, e, true); 16590792Sgshapiro } 16690792Sgshapiro } 16790792Sgshapiro } 16890792Sgshapiro} 16990792Sgshapiro 17090792Sgshapiro/* 17190792Sgshapiro** COLLECT_DFOPEN -- open the message data file 17290792Sgshapiro** 17390792Sgshapiro** Called by collect() after it has finished processing the header. 17490792Sgshapiro** Queue selection occurs at this point, possibly based on the 17590792Sgshapiro** envelope's recipient list and on header information. 17690792Sgshapiro** 17790792Sgshapiro** Parameters: 17890792Sgshapiro** e -- envelope 17990792Sgshapiro** 18090792Sgshapiro** Results: 18190792Sgshapiro** NULL, or a pointer to an open data file, 18290792Sgshapiro** into which the message body will be written by collect(). 18390792Sgshapiro** 18490792Sgshapiro** Side Effects: 18590792Sgshapiro** Calls syserr, sets EF_FATALERRS and returns NULL 18690792Sgshapiro** if there is insufficient disk space. 18790792Sgshapiro** Aborts process if data file could not be opened. 18890792Sgshapiro** Otherwise, the queue is selected, 18990792Sgshapiro** e->e_{dfino,dfdev,msgsize,flags} are updated, 19090792Sgshapiro** and a pointer to an open data file is returned. 19190792Sgshapiro*/ 19290792Sgshapiro 19390792Sgshapirostatic SM_FILE_T * 19490792Sgshapirocollect_dfopen(e) 19590792Sgshapiro ENVELOPE *e; 19690792Sgshapiro{ 19790792Sgshapiro MODE_T oldumask = 0; 19890792Sgshapiro int dfd; 19990792Sgshapiro struct stat stbuf; 20090792Sgshapiro SM_FILE_T *df; 20190792Sgshapiro char *dfname; 20290792Sgshapiro 20390792Sgshapiro if (!setnewqueue(e)) 20490792Sgshapiro return NULL; 20590792Sgshapiro 20690792Sgshapiro dfname = queuename(e, DATAFL_LETTER); 20790792Sgshapiro if (bitset(S_IWGRP, QueueFileMode)) 20890792Sgshapiro oldumask = umask(002); 20990792Sgshapiro df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 21090792Sgshapiro SFF_OPENASROOT); 21190792Sgshapiro if (bitset(S_IWGRP, QueueFileMode)) 21290792Sgshapiro (void) umask(oldumask); 21390792Sgshapiro if (df == NULL) 21490792Sgshapiro { 21590792Sgshapiro syserr("@Cannot create %s", dfname); 21690792Sgshapiro e->e_flags |= EF_NO_BODY_RETN; 21790792Sgshapiro flush_errors(true); 218120256Sgshapiro finis(false, true, ExitStat); 21990792Sgshapiro /* NOTREACHED */ 22090792Sgshapiro } 22190792Sgshapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 22290792Sgshapiro if (dfd < 0 || fstat(dfd, &stbuf) < 0) 22390792Sgshapiro e->e_dfino = -1; 22490792Sgshapiro else 22590792Sgshapiro { 22690792Sgshapiro e->e_dfdev = stbuf.st_dev; 22790792Sgshapiro e->e_dfino = stbuf.st_ino; 22890792Sgshapiro } 22990792Sgshapiro e->e_flags |= EF_HAS_DF; 23090792Sgshapiro return df; 23190792Sgshapiro} 23290792Sgshapiro 23390792Sgshapiro/* 23438032Speter** COLLECT -- read & parse message header & make temp file. 23538032Speter** 23638032Speter** Creates a temporary file name and copies the standard 23738032Speter** input to that file. Leading UNIX-style "From" lines are 23838032Speter** stripped off (after important information is extracted). 23938032Speter** 24038032Speter** Parameters: 24138032Speter** fp -- file to read. 24238032Speter** smtpmode -- if set, we are running SMTP: give an RFC821 24338032Speter** style message to say we are ready to collect 24438032Speter** input, and never ignore a single dot to mean 24538032Speter** end of message. 24638032Speter** hdrp -- the location to stash the header. 24738032Speter** e -- the current envelope. 248120256Sgshapiro** rsetsize -- reset e_msgsize? 24938032Speter** 25038032Speter** Returns: 25138032Speter** none. 25238032Speter** 25338032Speter** Side Effects: 25490792Sgshapiro** If successful, 25590792Sgshapiro** - Data file is created and filled, and e->e_dfp is set. 25690792Sgshapiro** - The from person may be set. 25790792Sgshapiro** If the "enough disk space" check fails, 25890792Sgshapiro** - syserr is called. 25990792Sgshapiro** - e->e_dfp is NULL. 26090792Sgshapiro** - e->e_flags & EF_FATALERRS is set. 26190792Sgshapiro** - collect() returns. 26290792Sgshapiro** If data file cannot be created, the process is terminated. 26338032Speter*/ 26438032Speter 26538032Speter/* values for input state machine */ 26638032Speter#define IS_NORM 0 /* middle of line */ 26738032Speter#define IS_BOL 1 /* beginning of line */ 26838032Speter#define IS_DOT 2 /* read a dot at beginning of line */ 26938032Speter#define IS_DOTCR 3 /* read ".\r" at beginning of line */ 27038032Speter#define IS_CR 4 /* read a carriage return */ 27138032Speter 27238032Speter/* values for message state machine */ 27338032Speter#define MS_UFROM 0 /* reading Unix from line */ 27438032Speter#define MS_HEADER 1 /* reading message header */ 27538032Speter#define MS_BODY 2 /* reading message body */ 27643148Speter#define MS_DISCARD 3 /* discarding rest of message */ 27738032Speter 27838032Spetervoid 279120256Sgshapirocollect(fp, smtpmode, hdrp, e, rsetsize) 28090792Sgshapiro SM_FILE_T *fp; 28138032Speter bool smtpmode; 28238032Speter HDR **hdrp; 28338032Speter register ENVELOPE *e; 284120256Sgshapiro bool rsetsize; 28538032Speter{ 286157001Sgshapiro register SM_FILE_T *df; 287157001Sgshapiro bool ignrdot; 288157001Sgshapiro int dbto; 289157001Sgshapiro register char *bp; 290157001Sgshapiro int c; 291157001Sgshapiro bool inputerr; 29238032Speter bool headeronly; 293157001Sgshapiro char *buf; 294157001Sgshapiro int buflen; 295157001Sgshapiro int istate; 296157001Sgshapiro int mstate; 297157001Sgshapiro int hdrslen; 298157001Sgshapiro int numhdrs; 299157001Sgshapiro int afd; 300285229Sgshapiro int old_rd_tmo; 301157001Sgshapiro unsigned char *pbp; 30290792Sgshapiro unsigned char peekbuf[8]; 30338032Speter char bufbuf[MAXLINE]; 304249729Sgshapiro#if _FFR_REJECT_NUL_BYTE 305249729Sgshapiro bool hasNUL; /* has at least one NUL input byte */ 306363466Sgshapiro#endif 30738032Speter 30890792Sgshapiro df = NULL; 30990792Sgshapiro ignrdot = smtpmode ? false : IgnrDot; 310157001Sgshapiro 311157001Sgshapiro /* timeout for I/O functions is in milliseconds */ 312157001Sgshapiro dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000) 313157001Sgshapiro : SM_TIME_FOREVER; 314157001Sgshapiro sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto); 315285229Sgshapiro old_rd_tmo = set_tls_rd_tmo(TimeOuts.to_datablock); 31690792Sgshapiro c = SM_IO_EOF; 31790792Sgshapiro inputerr = false; 31838032Speter headeronly = hdrp != NULL; 31990792Sgshapiro hdrslen = 0; 32090792Sgshapiro numhdrs = 0; 32190792Sgshapiro HasEightBits = false; 322249729Sgshapiro#if _FFR_REJECT_NUL_BYTE 323249729Sgshapiro hasNUL = false; 324363466Sgshapiro#endif 32590792Sgshapiro buf = bp = bufbuf; 326168515Sgshapiro buflen = sizeof(bufbuf); 32790792Sgshapiro pbp = peekbuf; 32890792Sgshapiro istate = IS_BOL; 32990792Sgshapiro mstate = SaveFrom ? MS_HEADER : MS_UFROM; 33038032Speter 33138032Speter /* 33238032Speter ** Tell ARPANET to go ahead. 33338032Speter */ 33438032Speter 33538032Speter if (smtpmode) 33638032Speter message("354 Enter mail, end with \".\" on a line by itself"); 33738032Speter 338157001Sgshapiro /* simulate an I/O timeout when used as sink */ 339157001Sgshapiro if (tTd(83, 101)) 340157001Sgshapiro sleep(319); 341157001Sgshapiro 34238032Speter if (tTd(30, 2)) 34390792Sgshapiro sm_dprintf("collect\n"); 34438032Speter 34538032Speter /* 34638032Speter ** Read the message. 34738032Speter ** 34838032Speter ** This is done using two interleaved state machines. 34938032Speter ** The input state machine is looking for things like 35038032Speter ** hidden dots; the message state machine is handling 35138032Speter ** the larger picture (e.g., header versus body). 35238032Speter */ 35338032Speter 354120256Sgshapiro if (rsetsize) 355120256Sgshapiro e->e_msgsize = 0; 35638032Speter for (;;) 35738032Speter { 35838032Speter if (tTd(30, 35)) 35990792Sgshapiro sm_dprintf("top, istate=%d, mstate=%d\n", istate, 36090792Sgshapiro mstate); 36138032Speter for (;;) 36238032Speter { 36338032Speter if (pbp > peekbuf) 36438032Speter c = *--pbp; 36538032Speter else 36638032Speter { 36790792Sgshapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 36838032Speter { 36938032Speter errno = 0; 37090792Sgshapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 37190792Sgshapiro if (c == SM_IO_EOF && errno == EINTR) 37266494Sgshapiro { 37366494Sgshapiro /* Interrupted, retry */ 37490792Sgshapiro sm_io_clearerr(fp); 37566494Sgshapiro continue; 37666494Sgshapiro } 377157001Sgshapiro 378157001Sgshapiro /* timeout? */ 379157001Sgshapiro if (c == SM_IO_EOF && errno == EAGAIN 380157001Sgshapiro && smtpmode) 381157001Sgshapiro { 382157001Sgshapiro /* 383157001Sgshapiro ** Override e_message in 384157001Sgshapiro ** usrerr() as this is the 385157001Sgshapiro ** reason for failure that 386157001Sgshapiro ** should be logged for 387157001Sgshapiro ** undelivered recipients. 388157001Sgshapiro */ 389157001Sgshapiro 390157001Sgshapiro e->e_message = NULL; 391157001Sgshapiro errno = 0; 392157001Sgshapiro inputerr = true; 393157001Sgshapiro goto readabort; 394157001Sgshapiro } 39566494Sgshapiro break; 39638032Speter } 39738032Speter if (TrafficLogFile != NULL && !headeronly) 39838032Speter { 39938032Speter if (istate == IS_BOL) 40090792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, 40190792Sgshapiro SM_TIME_DEFAULT, 40290792Sgshapiro "%05d <<< ", 40390792Sgshapiro (int) CurrentPid); 40490792Sgshapiro if (c == SM_IO_EOF) 40590792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, 40690792Sgshapiro SM_TIME_DEFAULT, 40790792Sgshapiro "[EOF]\n"); 40838032Speter else 40990792Sgshapiro (void) sm_io_putc(TrafficLogFile, 41090792Sgshapiro SM_TIME_DEFAULT, 41190792Sgshapiro c); 41238032Speter } 413249729Sgshapiro#if _FFR_REJECT_NUL_BYTE 414249729Sgshapiro if (c == '\0') 415249729Sgshapiro hasNUL = true; 416363466Sgshapiro#endif 41790792Sgshapiro if (c == SM_IO_EOF) 41838032Speter goto readerr; 41938032Speter if (SevenBitInput) 42038032Speter c &= 0x7f; 42138032Speter else 42238032Speter HasEightBits |= bitset(0x80, c); 42338032Speter } 42438032Speter if (tTd(30, 94)) 42590792Sgshapiro sm_dprintf("istate=%d, c=%c (0x%x)\n", 42664562Sgshapiro istate, (char) c, c); 42738032Speter switch (istate) 42838032Speter { 42938032Speter case IS_BOL: 43038032Speter if (c == '.') 43138032Speter { 43238032Speter istate = IS_DOT; 43338032Speter continue; 43438032Speter } 43538032Speter break; 43638032Speter 43738032Speter case IS_DOT: 438363466Sgshapiro if (c == '\n' && !ignrdot) 43938032Speter goto readerr; 440363466Sgshapiro else if (c == '\r') 44138032Speter { 44238032Speter istate = IS_DOTCR; 44338032Speter continue; 44438032Speter } 44594334Sgshapiro else if (ignrdot || 44694334Sgshapiro (c != '.' && 44794334Sgshapiro OpMode != MD_SMTP && 44838032Speter OpMode != MD_DAEMON && 44938032Speter OpMode != MD_ARPAFTP)) 45094334Sgshapiro 45138032Speter { 452157001Sgshapiro SM_ASSERT(pbp < peekbuf + 453157001Sgshapiro sizeof(peekbuf)); 45438032Speter *pbp++ = c; 45538032Speter c = '.'; 45638032Speter } 45738032Speter break; 45838032Speter 45938032Speter case IS_DOTCR: 46038032Speter if (c == '\n' && !ignrdot) 46138032Speter goto readerr; 46238032Speter else 46338032Speter { 46438032Speter /* push back the ".\rx" */ 465157001Sgshapiro SM_ASSERT(pbp < peekbuf + 466157001Sgshapiro sizeof(peekbuf)); 46738032Speter *pbp++ = c; 46894334Sgshapiro if (OpMode != MD_SMTP && 46994334Sgshapiro OpMode != MD_DAEMON && 47094334Sgshapiro OpMode != MD_ARPAFTP) 47194334Sgshapiro { 472112810Sgshapiro SM_ASSERT(pbp < peekbuf + 473112810Sgshapiro sizeof(peekbuf)); 47494334Sgshapiro *pbp++ = '\r'; 47594334Sgshapiro c = '.'; 47694334Sgshapiro } 47794334Sgshapiro else 47894334Sgshapiro c = '\r'; 47938032Speter } 48038032Speter break; 48138032Speter 48238032Speter case IS_CR: 48338032Speter if (c == '\n') 48438032Speter istate = IS_BOL; 48538032Speter else 48638032Speter { 48790792Sgshapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 48890792Sgshapiro c); 48938032Speter c = '\r'; 49038032Speter istate = IS_NORM; 49138032Speter } 49238032Speter goto bufferchar; 49338032Speter } 49438032Speter 495363466Sgshapiro if (c == '\r') 49638032Speter { 49738032Speter istate = IS_CR; 49838032Speter continue; 49938032Speter } 500363466Sgshapiro else if (c == '\n') 50138032Speter istate = IS_BOL; 50238032Speter else 50338032Speter istate = IS_NORM; 50438032Speter 50538032Speterbufferchar: 50638032Speter if (!headeronly) 50766494Sgshapiro { 50866494Sgshapiro /* no overflow? */ 50966494Sgshapiro if (e->e_msgsize >= 0) 51066494Sgshapiro { 51166494Sgshapiro e->e_msgsize++; 51266494Sgshapiro if (MaxMessageSize > 0 && 51366494Sgshapiro !bitset(EF_TOOBIG, e->e_flags) && 51466494Sgshapiro e->e_msgsize > MaxMessageSize) 51566494Sgshapiro e->e_flags |= EF_TOOBIG; 51666494Sgshapiro } 51766494Sgshapiro } 51843148Speter switch (mstate) 51938032Speter { 52043148Speter case MS_BODY: 52138032Speter /* just put the character out */ 52266494Sgshapiro if (!bitset(EF_TOOBIG, e->e_flags)) 52390792Sgshapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 52490792Sgshapiro c); 52590792Sgshapiro 52664562Sgshapiro /* FALLTHROUGH */ 52743148Speter 52843148Speter case MS_DISCARD: 52938032Speter continue; 53038032Speter } 53138032Speter 532141858Sgshapiro SM_ASSERT(mstate == MS_UFROM || mstate == MS_HEADER); 533141858Sgshapiro 53438032Speter /* header -- buffer up */ 53538032Speter if (bp >= &buf[buflen - 2]) 53638032Speter { 53738032Speter char *obuf; 53838032Speter 53938032Speter /* out of space for header */ 54038032Speter obuf = buf; 54138032Speter if (buflen < MEMCHUNKSIZE) 54238032Speter buflen *= 2; 54338032Speter else 54438032Speter buflen += MEMCHUNKSIZE; 545157001Sgshapiro if (buflen <= 0) 546157001Sgshapiro { 547157001Sgshapiro sm_syslog(LOG_NOTICE, e->e_id, 548157001Sgshapiro "header overflow from %s during message collect", 549157001Sgshapiro CURHOSTNAME); 550157001Sgshapiro errno = 0; 551157001Sgshapiro e->e_flags |= EF_CLRQUEUE; 552157001Sgshapiro e->e_status = "5.6.0"; 553157001Sgshapiro usrerrenh(e->e_status, 554157001Sgshapiro "552 Headers too large"); 555157001Sgshapiro goto discard; 556157001Sgshapiro } 55738032Speter buf = xalloc(buflen); 55864562Sgshapiro memmove(buf, obuf, bp - obuf); 55938032Speter bp = &buf[bp - obuf]; 56038032Speter if (obuf != bufbuf) 56190792Sgshapiro sm_free(obuf); /* XXX */ 56238032Speter } 56390792Sgshapiro 564168515Sgshapiro if (c != '\0') 56538032Speter { 56638032Speter *bp++ = c; 56790792Sgshapiro ++hdrslen; 56880785Sgshapiro if (!headeronly && 56980785Sgshapiro MaxHeadersLength > 0 && 57073188Sgshapiro hdrslen > MaxHeadersLength) 57143148Speter { 57243148Speter sm_syslog(LOG_NOTICE, e->e_id, 57343730Speter "headers too large (%d max) from %s during message collect", 57443730Speter MaxHeadersLength, 57590792Sgshapiro CURHOSTNAME); 57643148Speter errno = 0; 57743148Speter e->e_flags |= EF_CLRQUEUE; 57843148Speter e->e_status = "5.6.0"; 57964562Sgshapiro usrerrenh(e->e_status, 58064562Sgshapiro "552 Headers too large (%d max)", 58164562Sgshapiro MaxHeadersLength); 582157001Sgshapiro discard: 58343148Speter mstate = MS_DISCARD; 58443148Speter } 58543148Speter } 58638032Speter if (istate == IS_BOL) 58738032Speter break; 58838032Speter } 58938032Speter *bp = '\0'; 59038032Speter 59138032Speternextstate: 59238032Speter if (tTd(30, 35)) 593168515Sgshapiro sm_dprintf("nextstate, istate=%d, mstate=%d, line=\"%s\"\n", 59438032Speter istate, mstate, buf); 59538032Speter switch (mstate) 59638032Speter { 59738032Speter case MS_UFROM: 59838032Speter mstate = MS_HEADER; 59938032Speter#ifndef NOTUNIX 60038032Speter if (strncmp(buf, "From ", 5) == 0) 60138032Speter { 60238032Speter bp = buf; 60338032Speter eatfrom(buf, e); 60438032Speter continue; 60538032Speter } 60664562Sgshapiro#endif /* ! NOTUNIX */ 60764562Sgshapiro /* FALLTHROUGH */ 60838032Speter 60938032Speter case MS_HEADER: 61038032Speter if (!isheader(buf)) 61138032Speter { 61238032Speter mstate = MS_BODY; 61338032Speter goto nextstate; 61438032Speter } 61538032Speter 61638032Speter /* check for possible continuation line */ 61738032Speter do 61838032Speter { 61990792Sgshapiro sm_io_clearerr(fp); 62038032Speter errno = 0; 62190792Sgshapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 622157001Sgshapiro 623157001Sgshapiro /* timeout? */ 624157001Sgshapiro if (c == SM_IO_EOF && errno == EAGAIN 625157001Sgshapiro && smtpmode) 626157001Sgshapiro { 627157001Sgshapiro /* 628157001Sgshapiro ** Override e_message in 629157001Sgshapiro ** usrerr() as this is the 630157001Sgshapiro ** reason for failure that 631157001Sgshapiro ** should be logged for 632157001Sgshapiro ** undelivered recipients. 633157001Sgshapiro */ 634157001Sgshapiro 635157001Sgshapiro e->e_message = NULL; 636157001Sgshapiro errno = 0; 637157001Sgshapiro inputerr = true; 638157001Sgshapiro goto readabort; 639157001Sgshapiro } 64090792Sgshapiro } while (c == SM_IO_EOF && errno == EINTR); 64190792Sgshapiro if (c != SM_IO_EOF) 64290792Sgshapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 64338032Speter if (c == ' ' || c == '\t') 64438032Speter { 64538032Speter /* yep -- defer this */ 64638032Speter continue; 64738032Speter } 64838032Speter 649157001Sgshapiro SM_ASSERT(bp > buf); 650157001Sgshapiro 651157001Sgshapiro /* guaranteed by isheader(buf) */ 652157001Sgshapiro SM_ASSERT(*(bp - 1) != '\n' || bp > buf + 1); 653157001Sgshapiro 65438032Speter /* trim off trailing CRLF or NL */ 65538032Speter if (*--bp != '\n' || *--bp != '\r') 65638032Speter bp++; 65738032Speter *bp = '\0'; 65843148Speter 65964562Sgshapiro if (bitset(H_EOH, chompheader(buf, 66064562Sgshapiro CHHDR_CHECK | CHHDR_USER, 66164562Sgshapiro hdrp, e))) 66238032Speter { 66338032Speter mstate = MS_BODY; 66438032Speter goto nextstate; 66538032Speter } 66664562Sgshapiro numhdrs++; 66738032Speter break; 66838032Speter 66938032Speter case MS_BODY: 67038032Speter if (tTd(30, 1)) 67190792Sgshapiro sm_dprintf("EOH\n"); 67264562Sgshapiro 67338032Speter if (headeronly) 67438032Speter goto readerr; 67564562Sgshapiro 67690792Sgshapiro df = collect_eoh(e, numhdrs, hdrslen); 67790792Sgshapiro if (df == NULL) 67890792Sgshapiro e->e_flags |= EF_TOOBIG; 67964562Sgshapiro 68038032Speter bp = buf; 68138032Speter 68238032Speter /* toss blank line */ 683363466Sgshapiro if ((bp[0] == '\r' && bp[1] == '\n') || 684363466Sgshapiro (bp[0] == '\n')) 68538032Speter { 68638032Speter break; 68738032Speter } 68838032Speter 68938032Speter /* if not a blank separator, write it out */ 69066494Sgshapiro if (!bitset(EF_TOOBIG, e->e_flags)) 69138032Speter { 69238032Speter while (*bp != '\0') 69390792Sgshapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 69490792Sgshapiro *bp++); 69538032Speter } 69638032Speter break; 69738032Speter } 69838032Speter bp = buf; 69938032Speter } 70038032Speter 70138032Speterreaderr: 70290792Sgshapiro if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 70338032Speter { 70490792Sgshapiro const char *errmsg; 70538032Speter 70690792Sgshapiro if (sm_io_eof(fp)) 70790792Sgshapiro errmsg = "unexpected close"; 70890792Sgshapiro else 70990792Sgshapiro errmsg = sm_errstring(errno); 71038032Speter if (tTd(30, 1)) 71190792Sgshapiro sm_dprintf("collect: premature EOM: %s\n", errmsg); 71290792Sgshapiro if (LogLevel > 1) 71338032Speter sm_syslog(LOG_WARNING, e->e_id, 71438032Speter "collect: premature EOM: %s", errmsg); 71590792Sgshapiro inputerr = true; 71638032Speter } 71738032Speter 71838032Speter if (headeronly) 719285229Sgshapiro goto end; 72038032Speter 72190792Sgshapiro if (mstate != MS_BODY) 72290792Sgshapiro { 72390792Sgshapiro /* no body or discard, so we never opened the data file */ 72490792Sgshapiro SM_ASSERT(df == NULL); 72590792Sgshapiro df = collect_eoh(e, numhdrs, hdrslen); 72690792Sgshapiro } 72790792Sgshapiro 72864562Sgshapiro if (df == NULL) 72938032Speter { 73064562Sgshapiro /* skip next few clauses */ 73164562Sgshapiro /* EMPTY */ 73264562Sgshapiro } 73390792Sgshapiro else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 73464562Sgshapiro { 73590792Sgshapiro dferror(df, "sm_io_flush||sm_io_error", e); 73690792Sgshapiro flush_errors(true); 73790792Sgshapiro finis(true, true, ExitStat); 73864562Sgshapiro /* NOTREACHED */ 73938032Speter } 740132943Sgshapiro else if (SuperSafe == SAFE_NO || 741132943Sgshapiro SuperSafe == SAFE_INTERACTIVE || 742132943Sgshapiro (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode)) 74364562Sgshapiro { 74464562Sgshapiro /* skip next few clauses */ 74564562Sgshapiro /* EMPTY */ 746147078Sgshapiro /* Note: updfs() is not called in this case! */ 74764562Sgshapiro } 74890792Sgshapiro else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) 74964562Sgshapiro { 75064562Sgshapiro int save_errno = errno; 75138032Speter 75264562Sgshapiro if (save_errno == EEXIST) 75364562Sgshapiro { 75464562Sgshapiro char *dfile; 75564562Sgshapiro struct stat st; 75690792Sgshapiro int dfd; 75764562Sgshapiro 75890792Sgshapiro dfile = queuename(e, DATAFL_LETTER); 75964562Sgshapiro if (stat(dfile, &st) < 0) 76064562Sgshapiro st.st_size = -1; 76164562Sgshapiro errno = EEXIST; 762132943Sgshapiro syserr("@collect: bfcommit(%s): already on disk, size=%ld", 76366494Sgshapiro dfile, (long) st.st_size); 76490792Sgshapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 76564562Sgshapiro if (dfd >= 0) 76690792Sgshapiro dumpfd(dfd, true, true); 76764562Sgshapiro } 76864562Sgshapiro errno = save_errno; 76964562Sgshapiro dferror(df, "bfcommit", e); 77090792Sgshapiro flush_errors(true); 77190792Sgshapiro finis(save_errno != EEXIST, true, ExitStat); 77264562Sgshapiro } 773132943Sgshapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) 77473188Sgshapiro { 775132943Sgshapiro dferror(df, "sm_io_getinfo", e); 776132943Sgshapiro flush_errors(true); 777132943Sgshapiro finis(true, true, ExitStat); 778132943Sgshapiro /* NOTREACHED */ 779132943Sgshapiro } 780132943Sgshapiro else if (fsync(afd) < 0) 781132943Sgshapiro { 78290792Sgshapiro dferror(df, "fsync", e); 78390792Sgshapiro flush_errors(true); 78490792Sgshapiro finis(true, true, ExitStat); 78573188Sgshapiro /* NOTREACHED */ 78673188Sgshapiro } 78790792Sgshapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 78864562Sgshapiro { 78990792Sgshapiro dferror(df, "sm_io_close", e); 79090792Sgshapiro flush_errors(true); 79190792Sgshapiro finis(true, true, ExitStat); 79264562Sgshapiro /* NOTREACHED */ 79364562Sgshapiro } 79464562Sgshapiro else 79564562Sgshapiro { 79664562Sgshapiro /* everything is happily flushed to disk */ 79764562Sgshapiro df = NULL; 79890792Sgshapiro 79990792Sgshapiro /* remove from available space in filesystem */ 800147078Sgshapiro updfs(e, 0, 1, "collect"); 80164562Sgshapiro } 80264562Sgshapiro 80338032Speter /* An EOF when running SMTP is an error */ 804157001Sgshapiro readabort: 80538032Speter if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 80638032Speter { 80738032Speter char *host; 80838032Speter char *problem; 809102528Sgshapiro ADDRESS *q; 81038032Speter 81138032Speter host = RealHostName; 81238032Speter if (host == NULL) 81338032Speter host = "localhost"; 81438032Speter 81590792Sgshapiro if (sm_io_eof(fp)) 81638032Speter problem = "unexpected close"; 81790792Sgshapiro else if (sm_io_error(fp)) 81838032Speter problem = "I/O error"; 81938032Speter else 82038032Speter problem = "read timeout"; 82190792Sgshapiro if (LogLevel > 0 && sm_io_eof(fp)) 82238032Speter sm_syslog(LOG_NOTICE, e->e_id, 82390792Sgshapiro "collect: %s on connection from %.100s, sender=%s", 82490792Sgshapiro problem, host, 82590792Sgshapiro shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 82690792Sgshapiro if (sm_io_eof(fp)) 827157001Sgshapiro usrerr("421 4.4.1 collect: %s on connection from %s, from=%s", 82838032Speter problem, host, 82938032Speter shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 83038032Speter else 831157001Sgshapiro syserr("421 4.4.1 collect: %s on connection from %s, from=%s", 83238032Speter problem, host, 83338032Speter shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 834157001Sgshapiro flush_errors(true); 83538032Speter 83638032Speter /* don't return an error indication */ 83738032Speter e->e_to = NULL; 83838032Speter e->e_flags &= ~EF_FATALERRS; 83938032Speter e->e_flags |= EF_CLRQUEUE; 84038032Speter 841102528Sgshapiro /* Don't send any message notification to sender */ 842102528Sgshapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 843102528Sgshapiro { 844102528Sgshapiro if (QS_IS_DEAD(q->q_state)) 845102528Sgshapiro continue; 846102528Sgshapiro q->q_state = QS_FATALERR; 847102528Sgshapiro } 848102528Sgshapiro 849159609Sgshapiro (void) sm_io_close(df, SM_TIME_DEFAULT); 850159609Sgshapiro df = NULL; 85190792Sgshapiro finis(true, true, ExitStat); 85264562Sgshapiro /* NOTREACHED */ 85338032Speter } 85438032Speter 85590792Sgshapiro /* Log collection information. */ 856203004Sgshapiro if (tTd(92, 2)) 857203004Sgshapiro sm_dprintf("collect: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n", 858203004Sgshapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel); 85990792Sgshapiro if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 86038032Speter { 86190792Sgshapiro logsender(e, e->e_msgid); 86290792Sgshapiro e->e_flags &= ~EF_LOGSENDER; 86338032Speter } 86438032Speter 86538032Speter /* check for message too large */ 86666494Sgshapiro if (bitset(EF_TOOBIG, e->e_flags)) 86738032Speter { 86838032Speter e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 86990792Sgshapiro if (!bitset(EF_FATALERRS, e->e_flags)) 87090792Sgshapiro { 87190792Sgshapiro e->e_status = "5.2.3"; 87290792Sgshapiro usrerrenh(e->e_status, 87390792Sgshapiro "552 Message exceeds maximum fixed size (%ld)", 87490792Sgshapiro MaxMessageSize); 87590792Sgshapiro if (LogLevel > 6) 87690792Sgshapiro sm_syslog(LOG_NOTICE, e->e_id, 87790792Sgshapiro "message size (%ld) exceeds maximum (%ld)", 878244833Sgshapiro PRT_NONNEGL(e->e_msgsize), 879244833Sgshapiro MaxMessageSize); 88090792Sgshapiro } 88138032Speter } 88238032Speter 88338032Speter /* check for illegal 8-bit data */ 88438032Speter if (HasEightBits) 88538032Speter { 88638032Speter e->e_flags |= EF_HAS8BIT; 88738032Speter if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 88838032Speter !bitset(EF_IS_MIME, e->e_flags)) 88938032Speter { 89038032Speter e->e_status = "5.6.1"; 89164562Sgshapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 89238032Speter } 89338032Speter } 89438032Speter else 89538032Speter { 89638032Speter /* if it claimed to be 8 bits, well, it lied.... */ 89738032Speter if (e->e_bodytype != NULL && 89890792Sgshapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 89938032Speter e->e_bodytype = "7BIT"; 90038032Speter } 90138032Speter 902249729Sgshapiro#if _FFR_REJECT_NUL_BYTE 903249729Sgshapiro if (hasNUL && RejectNUL) 904249729Sgshapiro { 905249729Sgshapiro e->e_status = "5.6.1"; 906249729Sgshapiro usrerrenh(e->e_status, "554 NUL byte not allowed"); 907249729Sgshapiro } 908249729Sgshapiro#endif /* _FFR_REJECT_NUL_BYTE */ 909249729Sgshapiro 91090792Sgshapiro if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 91138032Speter { 91290792Sgshapiro char *dfname = queuename(e, DATAFL_LETTER); 91390792Sgshapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 914132943Sgshapiro SM_IO_RDONLY_B, NULL)) == NULL) 91564562Sgshapiro { 91664562Sgshapiro /* we haven't acked receipt yet, so just chuck this */ 91790792Sgshapiro syserr("@Cannot reopen %s", dfname); 91890792Sgshapiro finis(true, true, ExitStat); 91964562Sgshapiro /* NOTREACHED */ 92064562Sgshapiro } 92138032Speter } 92264562Sgshapiro else 92364562Sgshapiro e->e_dfp = df; 92494334Sgshapiro 92594334Sgshapiro /* collect statistics */ 92694334Sgshapiro if (OpMode != MD_VERIFY) 927120256Sgshapiro { 928120256Sgshapiro /* 929120256Sgshapiro ** Recalculate e_msgpriority, it is done at in eatheader() 930120256Sgshapiro ** which is called (in 8.12) after the header is collected, 931120256Sgshapiro ** hence e_msgsize is (most likely) incorrect. 932120256Sgshapiro */ 933120256Sgshapiro 934120256Sgshapiro e->e_msgpriority = e->e_msgsize 935120256Sgshapiro - e->e_class * WkClassFact 936120256Sgshapiro + e->e_nrcpts * WkRecipFact; 93794334Sgshapiro markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 938120256Sgshapiro } 939285229Sgshapiro 940285229Sgshapiro end: 941285229Sgshapiro (void) set_tls_rd_tmo(old_rd_tmo); 94238032Speter} 94338032Speter 94490792Sgshapiro/* 94564562Sgshapiro** DFERROR -- signal error on writing the data file. 94638032Speter** 94790792Sgshapiro** Called by collect(). Collect() always terminates the process 94890792Sgshapiro** immediately after calling dferror(), which means that the SMTP 94990792Sgshapiro** session will be terminated, which means that any error message 95090792Sgshapiro** issued by dferror must be a 421 error, as per RFC 821. 95190792Sgshapiro** 95238032Speter** Parameters: 95364562Sgshapiro** df -- the file pointer for the data file. 95464562Sgshapiro** msg -- detailed message. 95538032Speter** e -- the current envelope. 95638032Speter** 95738032Speter** Returns: 95838032Speter** none. 95938032Speter** 96038032Speter** Side Effects: 96138032Speter** Gives an error message. 96238032Speter** Arranges for following output to go elsewhere. 96338032Speter*/ 96438032Speter 965132943Sgshapirovoid 96664562Sgshapirodferror(df, msg, e) 96790792Sgshapiro SM_FILE_T *volatile df; 96864562Sgshapiro char *msg; 96938032Speter register ENVELOPE *e; 97038032Speter{ 97164562Sgshapiro char *dfname; 97264562Sgshapiro 97390792Sgshapiro dfname = queuename(e, DATAFL_LETTER); 97438032Speter setstat(EX_IOERR); 97538032Speter if (errno == ENOSPC) 97638032Speter { 97738032Speter#if STAT64 > 0 97838032Speter struct stat64 st; 979363466Sgshapiro#else 98038032Speter struct stat st; 981363466Sgshapiro#endif 98238032Speter long avail; 98338032Speter long bsize; 98438032Speter 98538032Speter e->e_flags |= EF_NO_BODY_RETN; 98638032Speter 98738032Speter if ( 98838032Speter#if STAT64 > 0 98990792Sgshapiro fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 990363466Sgshapiro#else 99190792Sgshapiro fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 992363466Sgshapiro#endif 99338032Speter < 0) 99438032Speter st.st_size = 0; 99590792Sgshapiro (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 996132943Sgshapiro SM_IO_WRONLY_B, NULL, df); 99738032Speter if (st.st_size <= 0) 99890792Sgshapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 99990792Sgshapiro "\n*** Mail could not be accepted"); 100038032Speter else 100190792Sgshapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 100290792Sgshapiro "\n*** Mail of at least %llu bytes could not be accepted\n", 100390792Sgshapiro (ULONGLONG_T) st.st_size); 100490792Sgshapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 100590792Sgshapiro "*** at %s due to lack of disk space for temp file.\n", 100638032Speter MyHostName); 100790792Sgshapiro avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 100890792Sgshapiro &bsize); 100938032Speter if (avail > 0) 101038032Speter { 101138032Speter if (bsize > 1024) 101238032Speter avail *= bsize / 1024; 101338032Speter else if (bsize < 1024) 101438032Speter avail /= 1024 / bsize; 101590792Sgshapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 101690792Sgshapiro "*** Currently, %ld kilobytes are available for mail temp files.\n", 101738032Speter avail); 101838032Speter } 101990792Sgshapiro#if 0 102090792Sgshapiro /* Wrong response code; should be 421. */ 102138032Speter e->e_status = "4.3.1"; 102264562Sgshapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 102390792Sgshapiro#else /* 0 */ 102490792Sgshapiro syserr("421 4.3.1 Out of disk space for temp file"); 102590792Sgshapiro#endif /* 0 */ 102638032Speter } 102738032Speter else 1028285229Sgshapiro syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%ld, gid=%ld)", 1029285229Sgshapiro dfname, msg, (long) geteuid(), (long) getegid()); 103090792Sgshapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 103190792Sgshapiro SM_IO_WRONLY, NULL, df) == NULL) 103238032Speter sm_syslog(LOG_ERR, e->e_id, 103390792Sgshapiro "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 103490792Sgshapiro sm_errstring(errno)); 103538032Speter} 103690792Sgshapiro/* 103738032Speter** EATFROM -- chew up a UNIX style from line and process 103838032Speter** 103938032Speter** This does indeed make some assumptions about the format 104038032Speter** of UNIX messages. 104138032Speter** 104238032Speter** Parameters: 104338032Speter** fm -- the from line. 1044120256Sgshapiro** e -- envelope 104538032Speter** 104638032Speter** Returns: 104738032Speter** none. 104838032Speter** 104938032Speter** Side Effects: 105038032Speter** extracts what information it can from the header, 105138032Speter** such as the date. 105238032Speter*/ 105338032Speter 105464562Sgshapiro#ifndef NOTUNIX 105538032Speter 105664562Sgshapirostatic char *DowList[] = 105738032Speter{ 105838032Speter "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 105938032Speter}; 106038032Speter 106164562Sgshapirostatic char *MonthList[] = 106238032Speter{ 106338032Speter "Jan", "Feb", "Mar", "Apr", "May", "Jun", 106438032Speter "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 106538032Speter NULL 106638032Speter}; 106738032Speter 106864562Sgshapirostatic void 106938032Spetereatfrom(fm, e) 107038032Speter char *volatile fm; 107138032Speter register ENVELOPE *e; 107238032Speter{ 107338032Speter register char *p; 107438032Speter register char **dt; 107538032Speter 107638032Speter if (tTd(30, 2)) 107790792Sgshapiro sm_dprintf("eatfrom(%s)\n", fm); 107838032Speter 107938032Speter /* find the date part */ 108038032Speter p = fm; 108138032Speter while (*p != '\0') 108238032Speter { 108338032Speter /* skip a word */ 108438032Speter while (*p != '\0' && *p != ' ') 108538032Speter p++; 108638032Speter while (*p == ' ') 108738032Speter p++; 108871345Sgshapiro if (strlen(p) < 17) 108971345Sgshapiro { 109071345Sgshapiro /* no room for the date */ 109171345Sgshapiro return; 109271345Sgshapiro } 109338032Speter if (!(isascii(*p) && isupper(*p)) || 109438032Speter p[3] != ' ' || p[13] != ':' || p[16] != ':') 109538032Speter continue; 109638032Speter 109738032Speter /* we have a possible date */ 109838032Speter for (dt = DowList; *dt != NULL; dt++) 109938032Speter if (strncmp(*dt, p, 3) == 0) 110038032Speter break; 110138032Speter if (*dt == NULL) 110238032Speter continue; 110338032Speter 110438032Speter for (dt = MonthList; *dt != NULL; dt++) 110571345Sgshapiro { 110638032Speter if (strncmp(*dt, &p[4], 3) == 0) 110738032Speter break; 110871345Sgshapiro } 110938032Speter if (*dt != NULL) 111038032Speter break; 111138032Speter } 111238032Speter 111338032Speter if (*p != '\0') 111438032Speter { 111590792Sgshapiro char *q, buf[25]; 111638032Speter 111738032Speter /* we have found a date */ 111890792Sgshapiro (void) sm_strlcpy(buf, p, sizeof(buf)); 111990792Sgshapiro q = arpadate(buf); 112090792Sgshapiro macdefine(&e->e_macro, A_TEMP, 'a', q); 112138032Speter } 112238032Speter} 112364562Sgshapiro#endif /* ! NOTUNIX */ 1124