1c2aa98e2SPeter Wemm /* 2e92d3f3fSGregory Neil Shapiro * Copyright (c) 1998-2004 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 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 15c2aa98e2SPeter Wemm 16b6bacd31SGregory Neil Shapiro SM_RCSID("@(#)$Id: collect.c,v 8.260 2004/11/30 23:29:15 ca Exp $") 1706f25ae9SGregory Neil Shapiro 18b6bacd31SGregory Neil Shapiro static void collecttimeout __P((int)); 1906f25ae9SGregory Neil Shapiro static void eatfrom __P((char *volatile, ENVELOPE *)); 2040266059SGregory Neil Shapiro static void collect_doheader __P((ENVELOPE *)); 2140266059SGregory Neil Shapiro static SM_FILE_T *collect_dfopen __P((ENVELOPE *)); 2240266059SGregory Neil Shapiro static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int)); 2306f25ae9SGregory Neil Shapiro 2440266059SGregory Neil Shapiro /* 2540266059SGregory Neil Shapiro ** COLLECT_EOH -- end-of-header processing in collect() 2640266059SGregory Neil Shapiro ** 2740266059SGregory Neil Shapiro ** Called by collect() when it encounters the blank line 2840266059SGregory Neil Shapiro ** separating the header from the message body, or when it 2940266059SGregory Neil Shapiro ** encounters EOF in a message that contains only a header. 3040266059SGregory Neil Shapiro ** 3140266059SGregory Neil Shapiro ** Parameters: 3240266059SGregory Neil Shapiro ** e -- envelope 3340266059SGregory Neil Shapiro ** numhdrs -- number of headers 3440266059SGregory Neil Shapiro ** hdrslen -- length of headers 3540266059SGregory Neil Shapiro ** 3640266059SGregory Neil Shapiro ** Results: 3740266059SGregory Neil Shapiro ** NULL, or handle to open data file 3840266059SGregory Neil Shapiro ** 3940266059SGregory Neil Shapiro ** Side Effects: 4040266059SGregory Neil Shapiro ** end-of-header check ruleset is invoked. 4140266059SGregory Neil Shapiro ** envelope state is updated. 4240266059SGregory Neil Shapiro ** headers may be added and deleted. 4340266059SGregory Neil Shapiro ** selects the queue. 4440266059SGregory Neil Shapiro ** opens the data file. 4540266059SGregory Neil Shapiro */ 4640266059SGregory Neil Shapiro 4740266059SGregory Neil Shapiro static SM_FILE_T * 4840266059SGregory Neil Shapiro collect_eoh(e, numhdrs, hdrslen) 4940266059SGregory Neil Shapiro ENVELOPE *e; 5040266059SGregory Neil Shapiro int numhdrs; 5140266059SGregory Neil Shapiro int hdrslen; 5240266059SGregory Neil Shapiro { 5340266059SGregory Neil Shapiro char hnum[16]; 5440266059SGregory Neil Shapiro char hsize[16]; 5540266059SGregory Neil Shapiro 5640266059SGregory Neil Shapiro /* call the end-of-header check ruleset */ 5740266059SGregory Neil Shapiro (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs); 5840266059SGregory Neil Shapiro (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen); 5940266059SGregory Neil Shapiro if (tTd(30, 10)) 6040266059SGregory Neil Shapiro sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 6140266059SGregory Neil Shapiro hnum, hsize); 62959366dcSGregory Neil Shapiro (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT, 63959366dcSGregory Neil Shapiro 3, NULL, e->e_id); 6440266059SGregory Neil Shapiro 6540266059SGregory Neil Shapiro /* 6640266059SGregory Neil Shapiro ** Process the header, 6740266059SGregory Neil Shapiro ** select the queue, open the data file. 6840266059SGregory Neil Shapiro */ 6940266059SGregory Neil Shapiro 7040266059SGregory Neil Shapiro collect_doheader(e); 7140266059SGregory Neil Shapiro return collect_dfopen(e); 7240266059SGregory Neil Shapiro } 7340266059SGregory Neil Shapiro 7440266059SGregory Neil Shapiro /* 7540266059SGregory Neil Shapiro ** COLLECT_DOHEADER -- process header in collect() 7640266059SGregory Neil Shapiro ** 7740266059SGregory Neil Shapiro ** Called by collect() after it has finished parsing the header, 7840266059SGregory Neil Shapiro ** but before it selects the queue and creates the data file. 7940266059SGregory Neil Shapiro ** The results of processing the header will affect queue selection. 8040266059SGregory Neil Shapiro ** 8140266059SGregory Neil Shapiro ** Parameters: 8240266059SGregory Neil Shapiro ** e -- envelope 8340266059SGregory Neil Shapiro ** 8440266059SGregory Neil Shapiro ** Results: 8540266059SGregory Neil Shapiro ** none. 8640266059SGregory Neil Shapiro ** 8740266059SGregory Neil Shapiro ** Side Effects: 8840266059SGregory Neil Shapiro ** envelope state is updated. 8940266059SGregory Neil Shapiro ** headers may be added and deleted. 9040266059SGregory Neil Shapiro */ 9140266059SGregory Neil Shapiro 9240266059SGregory Neil Shapiro static void 9340266059SGregory Neil Shapiro collect_doheader(e) 9440266059SGregory Neil Shapiro ENVELOPE *e; 9540266059SGregory Neil Shapiro { 9640266059SGregory Neil Shapiro /* 9740266059SGregory Neil Shapiro ** Find out some information from the headers. 9840266059SGregory Neil Shapiro ** Examples are who is the from person & the date. 9940266059SGregory Neil Shapiro */ 10040266059SGregory Neil Shapiro 10140266059SGregory Neil Shapiro eatheader(e, true, false); 10240266059SGregory Neil Shapiro 10340266059SGregory Neil Shapiro if (GrabTo && e->e_sendqueue == NULL) 10440266059SGregory Neil Shapiro usrerr("No recipient addresses found in header"); 10540266059SGregory Neil Shapiro 10640266059SGregory Neil Shapiro /* 10740266059SGregory Neil Shapiro ** If we have a Return-Receipt-To:, turn it into a DSN. 10840266059SGregory Neil Shapiro */ 10940266059SGregory Neil Shapiro 11040266059SGregory Neil Shapiro if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 11140266059SGregory Neil Shapiro { 11240266059SGregory Neil Shapiro ADDRESS *q; 11340266059SGregory Neil Shapiro 11440266059SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 11540266059SGregory Neil Shapiro if (!bitset(QHASNOTIFY, q->q_flags)) 11640266059SGregory Neil Shapiro q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 11740266059SGregory Neil Shapiro } 11840266059SGregory Neil Shapiro 11940266059SGregory Neil Shapiro /* 12040266059SGregory Neil Shapiro ** Add an appropriate recipient line if we have none. 12140266059SGregory Neil Shapiro */ 12240266059SGregory Neil Shapiro 12340266059SGregory Neil Shapiro if (hvalue("to", e->e_header) != NULL || 12440266059SGregory Neil Shapiro hvalue("cc", e->e_header) != NULL || 12540266059SGregory Neil Shapiro hvalue("apparently-to", e->e_header) != NULL) 12640266059SGregory Neil Shapiro { 12740266059SGregory Neil Shapiro /* have a valid recipient header -- delete Bcc: headers */ 12840266059SGregory Neil Shapiro e->e_flags |= EF_DELETE_BCC; 12940266059SGregory Neil Shapiro } 13040266059SGregory Neil Shapiro else if (hvalue("bcc", e->e_header) == NULL) 13140266059SGregory Neil Shapiro { 13240266059SGregory Neil Shapiro /* no valid recipient headers */ 13340266059SGregory Neil Shapiro register ADDRESS *q; 13440266059SGregory Neil Shapiro char *hdr = NULL; 13540266059SGregory Neil Shapiro 13640266059SGregory Neil Shapiro /* create a recipient field */ 13740266059SGregory Neil Shapiro switch (NoRecipientAction) 13840266059SGregory Neil Shapiro { 13940266059SGregory Neil Shapiro case NRA_ADD_APPARENTLY_TO: 14040266059SGregory Neil Shapiro hdr = "Apparently-To"; 14140266059SGregory Neil Shapiro break; 14240266059SGregory Neil Shapiro 14340266059SGregory Neil Shapiro case NRA_ADD_TO: 14440266059SGregory Neil Shapiro hdr = "To"; 14540266059SGregory Neil Shapiro break; 14640266059SGregory Neil Shapiro 14740266059SGregory Neil Shapiro case NRA_ADD_BCC: 14840266059SGregory Neil Shapiro addheader("Bcc", " ", 0, e); 14940266059SGregory Neil Shapiro break; 15040266059SGregory Neil Shapiro 15140266059SGregory Neil Shapiro case NRA_ADD_TO_UNDISCLOSED: 15240266059SGregory Neil Shapiro addheader("To", "undisclosed-recipients:;", 0, e); 15340266059SGregory Neil Shapiro break; 15440266059SGregory Neil Shapiro } 15540266059SGregory Neil Shapiro 15640266059SGregory Neil Shapiro if (hdr != NULL) 15740266059SGregory Neil Shapiro { 15840266059SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15940266059SGregory Neil Shapiro { 16040266059SGregory Neil Shapiro if (q->q_alias != NULL) 16140266059SGregory Neil Shapiro continue; 16240266059SGregory Neil Shapiro if (tTd(30, 3)) 16340266059SGregory Neil Shapiro sm_dprintf("Adding %s: %s\n", 16440266059SGregory Neil Shapiro hdr, q->q_paddr); 16540266059SGregory Neil Shapiro addheader(hdr, q->q_paddr, 0, e); 16640266059SGregory Neil Shapiro } 16740266059SGregory Neil Shapiro } 16840266059SGregory Neil Shapiro } 16940266059SGregory Neil Shapiro } 17040266059SGregory Neil Shapiro 17140266059SGregory Neil Shapiro /* 17240266059SGregory Neil Shapiro ** COLLECT_DFOPEN -- open the message data file 17340266059SGregory Neil Shapiro ** 17440266059SGregory Neil Shapiro ** Called by collect() after it has finished processing the header. 17540266059SGregory Neil Shapiro ** Queue selection occurs at this point, possibly based on the 17640266059SGregory Neil Shapiro ** envelope's recipient list and on header information. 17740266059SGregory Neil Shapiro ** 17840266059SGregory Neil Shapiro ** Parameters: 17940266059SGregory Neil Shapiro ** e -- envelope 18040266059SGregory Neil Shapiro ** 18140266059SGregory Neil Shapiro ** Results: 18240266059SGregory Neil Shapiro ** NULL, or a pointer to an open data file, 18340266059SGregory Neil Shapiro ** into which the message body will be written by collect(). 18440266059SGregory Neil Shapiro ** 18540266059SGregory Neil Shapiro ** Side Effects: 18640266059SGregory Neil Shapiro ** Calls syserr, sets EF_FATALERRS and returns NULL 18740266059SGregory Neil Shapiro ** if there is insufficient disk space. 18840266059SGregory Neil Shapiro ** Aborts process if data file could not be opened. 18940266059SGregory Neil Shapiro ** Otherwise, the queue is selected, 19040266059SGregory Neil Shapiro ** e->e_{dfino,dfdev,msgsize,flags} are updated, 19140266059SGregory Neil Shapiro ** and a pointer to an open data file is returned. 19240266059SGregory Neil Shapiro */ 19340266059SGregory Neil Shapiro 19440266059SGregory Neil Shapiro static SM_FILE_T * 19540266059SGregory Neil Shapiro collect_dfopen(e) 19640266059SGregory Neil Shapiro ENVELOPE *e; 19740266059SGregory Neil Shapiro { 19840266059SGregory Neil Shapiro MODE_T oldumask = 0; 19940266059SGregory Neil Shapiro int dfd; 20040266059SGregory Neil Shapiro struct stat stbuf; 20140266059SGregory Neil Shapiro SM_FILE_T *df; 20240266059SGregory Neil Shapiro char *dfname; 20340266059SGregory Neil Shapiro 20440266059SGregory Neil Shapiro if (!setnewqueue(e)) 20540266059SGregory Neil Shapiro return NULL; 20640266059SGregory Neil Shapiro 20740266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 20840266059SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 20940266059SGregory Neil Shapiro oldumask = umask(002); 21040266059SGregory Neil Shapiro df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 21140266059SGregory Neil Shapiro SFF_OPENASROOT); 21240266059SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 21340266059SGregory Neil Shapiro (void) umask(oldumask); 21440266059SGregory Neil Shapiro if (df == NULL) 21540266059SGregory Neil Shapiro { 21640266059SGregory Neil Shapiro syserr("@Cannot create %s", dfname); 21740266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 21840266059SGregory Neil Shapiro flush_errors(true); 219a7ec597cSGregory Neil Shapiro finis(false, true, ExitStat); 22040266059SGregory Neil Shapiro /* NOTREACHED */ 22140266059SGregory Neil Shapiro } 22240266059SGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 22340266059SGregory Neil Shapiro if (dfd < 0 || fstat(dfd, &stbuf) < 0) 22440266059SGregory Neil Shapiro e->e_dfino = -1; 22540266059SGregory Neil Shapiro else 22640266059SGregory Neil Shapiro { 22740266059SGregory Neil Shapiro e->e_dfdev = stbuf.st_dev; 22840266059SGregory Neil Shapiro e->e_dfino = stbuf.st_ino; 22940266059SGregory Neil Shapiro } 23040266059SGregory Neil Shapiro e->e_flags |= EF_HAS_DF; 23140266059SGregory Neil Shapiro return df; 23240266059SGregory Neil Shapiro } 23340266059SGregory Neil Shapiro 23440266059SGregory Neil Shapiro /* 235c2aa98e2SPeter Wemm ** COLLECT -- read & parse message header & make temp file. 236c2aa98e2SPeter Wemm ** 237c2aa98e2SPeter Wemm ** Creates a temporary file name and copies the standard 238c2aa98e2SPeter Wemm ** input to that file. Leading UNIX-style "From" lines are 239c2aa98e2SPeter Wemm ** stripped off (after important information is extracted). 240c2aa98e2SPeter Wemm ** 241c2aa98e2SPeter Wemm ** Parameters: 242c2aa98e2SPeter Wemm ** fp -- file to read. 243c2aa98e2SPeter Wemm ** smtpmode -- if set, we are running SMTP: give an RFC821 244c2aa98e2SPeter Wemm ** style message to say we are ready to collect 245c2aa98e2SPeter Wemm ** input, and never ignore a single dot to mean 246c2aa98e2SPeter Wemm ** end of message. 247c2aa98e2SPeter Wemm ** hdrp -- the location to stash the header. 248c2aa98e2SPeter Wemm ** e -- the current envelope. 249a7ec597cSGregory Neil Shapiro ** rsetsize -- reset e_msgsize? 250c2aa98e2SPeter Wemm ** 251c2aa98e2SPeter Wemm ** Returns: 252c2aa98e2SPeter Wemm ** none. 253c2aa98e2SPeter Wemm ** 254c2aa98e2SPeter Wemm ** Side Effects: 25540266059SGregory Neil Shapiro ** If successful, 25640266059SGregory Neil Shapiro ** - Data file is created and filled, and e->e_dfp is set. 25740266059SGregory Neil Shapiro ** - The from person may be set. 25840266059SGregory Neil Shapiro ** If the "enough disk space" check fails, 25940266059SGregory Neil Shapiro ** - syserr is called. 26040266059SGregory Neil Shapiro ** - e->e_dfp is NULL. 26140266059SGregory Neil Shapiro ** - e->e_flags & EF_FATALERRS is set. 26240266059SGregory Neil Shapiro ** - collect() returns. 26340266059SGregory Neil Shapiro ** If data file cannot be created, the process is terminated. 264c2aa98e2SPeter Wemm */ 265c2aa98e2SPeter Wemm 266c2aa98e2SPeter Wemm static jmp_buf CtxCollectTimeout; 2678774250cSGregory Neil Shapiro static bool volatile CollectProgress; 26840266059SGregory Neil Shapiro static SM_EVENT *volatile CollectTimeout = NULL; 269c2aa98e2SPeter Wemm 270c2aa98e2SPeter Wemm /* values for input state machine */ 271c2aa98e2SPeter Wemm #define IS_NORM 0 /* middle of line */ 272c2aa98e2SPeter Wemm #define IS_BOL 1 /* beginning of line */ 273c2aa98e2SPeter Wemm #define IS_DOT 2 /* read a dot at beginning of line */ 274c2aa98e2SPeter Wemm #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 275c2aa98e2SPeter Wemm #define IS_CR 4 /* read a carriage return */ 276c2aa98e2SPeter Wemm 277c2aa98e2SPeter Wemm /* values for message state machine */ 278c2aa98e2SPeter Wemm #define MS_UFROM 0 /* reading Unix from line */ 279c2aa98e2SPeter Wemm #define MS_HEADER 1 /* reading message header */ 280c2aa98e2SPeter Wemm #define MS_BODY 2 /* reading message body */ 28125bab6e9SPeter Wemm #define MS_DISCARD 3 /* discarding rest of message */ 282c2aa98e2SPeter Wemm 283c2aa98e2SPeter Wemm void 284a7ec597cSGregory Neil Shapiro collect(fp, smtpmode, hdrp, e, rsetsize) 28540266059SGregory Neil Shapiro SM_FILE_T *fp; 286c2aa98e2SPeter Wemm bool smtpmode; 287c2aa98e2SPeter Wemm HDR **hdrp; 288c2aa98e2SPeter Wemm register ENVELOPE *e; 289a7ec597cSGregory Neil Shapiro bool rsetsize; 290c2aa98e2SPeter Wemm { 29140266059SGregory Neil Shapiro register SM_FILE_T *volatile df; 29240266059SGregory Neil Shapiro volatile bool ignrdot; 293b6bacd31SGregory Neil Shapiro volatile int dbto; 294c2aa98e2SPeter Wemm register char *volatile bp; 29540266059SGregory Neil Shapiro volatile int c; 29640266059SGregory Neil Shapiro volatile bool inputerr; 297c2aa98e2SPeter Wemm bool headeronly; 298c2aa98e2SPeter Wemm char *volatile buf; 299c2aa98e2SPeter Wemm volatile int buflen; 300c2aa98e2SPeter Wemm volatile int istate; 301c2aa98e2SPeter Wemm volatile int mstate; 30240266059SGregory Neil Shapiro volatile int hdrslen; 30340266059SGregory Neil Shapiro volatile int numhdrs; 30440266059SGregory Neil Shapiro volatile int afd; 30540266059SGregory Neil Shapiro unsigned char *volatile pbp; 30640266059SGregory Neil Shapiro unsigned char peekbuf[8]; 307c2aa98e2SPeter Wemm char bufbuf[MAXLINE]; 308c2aa98e2SPeter Wemm 30940266059SGregory Neil Shapiro df = NULL; 31040266059SGregory Neil Shapiro ignrdot = smtpmode ? false : IgnrDot; 311b6bacd31SGregory Neil Shapiro dbto = smtpmode ? (int) TimeOuts.to_datablock : 0; 31240266059SGregory Neil Shapiro c = SM_IO_EOF; 31340266059SGregory Neil Shapiro inputerr = false; 314c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 31540266059SGregory Neil Shapiro hdrslen = 0; 31640266059SGregory Neil Shapiro numhdrs = 0; 31740266059SGregory Neil Shapiro HasEightBits = false; 31840266059SGregory Neil Shapiro buf = bp = bufbuf; 31940266059SGregory Neil Shapiro buflen = sizeof bufbuf; 32040266059SGregory Neil Shapiro pbp = peekbuf; 32140266059SGregory Neil Shapiro istate = IS_BOL; 32240266059SGregory Neil Shapiro mstate = SaveFrom ? MS_HEADER : MS_UFROM; 32340266059SGregory Neil Shapiro CollectProgress = false; 324c2aa98e2SPeter Wemm 325c2aa98e2SPeter Wemm /* 326c2aa98e2SPeter Wemm ** Tell ARPANET to go ahead. 327c2aa98e2SPeter Wemm */ 328c2aa98e2SPeter Wemm 329c2aa98e2SPeter Wemm if (smtpmode) 330c2aa98e2SPeter Wemm message("354 Enter mail, end with \".\" on a line by itself"); 331c2aa98e2SPeter Wemm 332c2aa98e2SPeter Wemm if (tTd(30, 2)) 33340266059SGregory Neil Shapiro sm_dprintf("collect\n"); 334c2aa98e2SPeter Wemm 335c2aa98e2SPeter Wemm /* 336c2aa98e2SPeter Wemm ** Read the message. 337c2aa98e2SPeter Wemm ** 338c2aa98e2SPeter Wemm ** This is done using two interleaved state machines. 339c2aa98e2SPeter Wemm ** The input state machine is looking for things like 340c2aa98e2SPeter Wemm ** hidden dots; the message state machine is handling 341c2aa98e2SPeter Wemm ** the larger picture (e.g., header versus body). 342c2aa98e2SPeter Wemm */ 343c2aa98e2SPeter Wemm 344c2aa98e2SPeter Wemm if (dbto != 0) 345c2aa98e2SPeter Wemm { 346c2aa98e2SPeter Wemm /* handle possible input timeout */ 347c2aa98e2SPeter Wemm if (setjmp(CtxCollectTimeout) != 0) 348c2aa98e2SPeter Wemm { 349c2aa98e2SPeter Wemm if (LogLevel > 2) 350c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 351c2aa98e2SPeter Wemm "timeout waiting for input from %s during message collect", 35240266059SGregory Neil Shapiro CURHOSTNAME); 353c2aa98e2SPeter Wemm errno = 0; 35413bd1963SGregory Neil Shapiro if (smtpmode) 35513bd1963SGregory Neil Shapiro { 35613bd1963SGregory Neil Shapiro /* 35713bd1963SGregory Neil Shapiro ** Override e_message in usrerr() as this 35813bd1963SGregory Neil Shapiro ** is the reason for failure that should 35913bd1963SGregory Neil Shapiro ** be logged for undelivered recipients. 36013bd1963SGregory Neil Shapiro */ 36113bd1963SGregory Neil Shapiro 36213bd1963SGregory Neil Shapiro e->e_message = NULL; 36313bd1963SGregory Neil Shapiro } 36406f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 timeout waiting for input during message collect"); 365c2aa98e2SPeter Wemm goto readerr; 366c2aa98e2SPeter Wemm } 36740266059SGregory Neil Shapiro CollectTimeout = sm_setevent(dbto, collecttimeout, dbto); 368c2aa98e2SPeter Wemm } 369c2aa98e2SPeter Wemm 370a7ec597cSGregory Neil Shapiro if (rsetsize) 37140266059SGregory Neil Shapiro e->e_msgsize = 0; 372c2aa98e2SPeter Wemm for (;;) 373c2aa98e2SPeter Wemm { 374c2aa98e2SPeter Wemm if (tTd(30, 35)) 37540266059SGregory Neil Shapiro sm_dprintf("top, istate=%d, mstate=%d\n", istate, 37640266059SGregory Neil Shapiro mstate); 377c2aa98e2SPeter Wemm for (;;) 378c2aa98e2SPeter Wemm { 379c2aa98e2SPeter Wemm if (pbp > peekbuf) 380c2aa98e2SPeter Wemm c = *--pbp; 381c2aa98e2SPeter Wemm else 382c2aa98e2SPeter Wemm { 38340266059SGregory Neil Shapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 384c2aa98e2SPeter Wemm { 385c2aa98e2SPeter Wemm errno = 0; 38640266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 38740266059SGregory Neil Shapiro if (c == SM_IO_EOF && errno == EINTR) 38842e5d165SGregory Neil Shapiro { 38942e5d165SGregory Neil Shapiro /* Interrupted, retry */ 39040266059SGregory Neil Shapiro sm_io_clearerr(fp); 39142e5d165SGregory Neil Shapiro continue; 39242e5d165SGregory Neil Shapiro } 39342e5d165SGregory Neil Shapiro break; 394c2aa98e2SPeter Wemm } 39540266059SGregory Neil Shapiro CollectProgress = true; 396c2aa98e2SPeter Wemm if (TrafficLogFile != NULL && !headeronly) 397c2aa98e2SPeter Wemm { 398c2aa98e2SPeter Wemm if (istate == IS_BOL) 39940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 40040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 4018774250cSGregory Neil Shapiro "%05d <<< ", 40240266059SGregory Neil Shapiro (int) CurrentPid); 40340266059SGregory Neil Shapiro if (c == SM_IO_EOF) 40440266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 40540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 4068774250cSGregory Neil Shapiro "[EOF]\n"); 407c2aa98e2SPeter Wemm else 40840266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 40940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 41040266059SGregory Neil Shapiro c); 411c2aa98e2SPeter Wemm } 41240266059SGregory Neil Shapiro if (c == SM_IO_EOF) 413c2aa98e2SPeter Wemm goto readerr; 414c2aa98e2SPeter Wemm if (SevenBitInput) 415c2aa98e2SPeter Wemm c &= 0x7f; 416c2aa98e2SPeter Wemm else 417c2aa98e2SPeter Wemm HasEightBits |= bitset(0x80, c); 418c2aa98e2SPeter Wemm } 419c2aa98e2SPeter Wemm if (tTd(30, 94)) 42040266059SGregory Neil Shapiro sm_dprintf("istate=%d, c=%c (0x%x)\n", 42106f25ae9SGregory Neil Shapiro istate, (char) c, c); 422c2aa98e2SPeter Wemm switch (istate) 423c2aa98e2SPeter Wemm { 424c2aa98e2SPeter Wemm case IS_BOL: 425c2aa98e2SPeter Wemm if (c == '.') 426c2aa98e2SPeter Wemm { 427c2aa98e2SPeter Wemm istate = IS_DOT; 428c2aa98e2SPeter Wemm continue; 429c2aa98e2SPeter Wemm } 430c2aa98e2SPeter Wemm break; 431c2aa98e2SPeter Wemm 432c2aa98e2SPeter Wemm case IS_DOT: 433c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot && 434c2aa98e2SPeter Wemm !bitset(EF_NL_NOT_EOL, e->e_flags)) 435c2aa98e2SPeter Wemm goto readerr; 436c2aa98e2SPeter Wemm else if (c == '\r' && 437c2aa98e2SPeter Wemm !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 438c2aa98e2SPeter Wemm { 439c2aa98e2SPeter Wemm istate = IS_DOTCR; 440c2aa98e2SPeter Wemm continue; 441c2aa98e2SPeter Wemm } 442605302a5SGregory Neil Shapiro else if (ignrdot || 443605302a5SGregory Neil Shapiro (c != '.' && 444605302a5SGregory Neil Shapiro OpMode != MD_SMTP && 445c2aa98e2SPeter Wemm OpMode != MD_DAEMON && 446c2aa98e2SPeter Wemm OpMode != MD_ARPAFTP)) 447605302a5SGregory Neil Shapiro 448c2aa98e2SPeter Wemm { 4495ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 450c2aa98e2SPeter Wemm *pbp++ = c; 451c2aa98e2SPeter Wemm c = '.'; 452c2aa98e2SPeter Wemm } 453c2aa98e2SPeter Wemm break; 454c2aa98e2SPeter Wemm 455c2aa98e2SPeter Wemm case IS_DOTCR: 456c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot) 457c2aa98e2SPeter Wemm goto readerr; 458c2aa98e2SPeter Wemm else 459c2aa98e2SPeter Wemm { 460c2aa98e2SPeter Wemm /* push back the ".\rx" */ 4615ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 462c2aa98e2SPeter Wemm *pbp++ = c; 463605302a5SGregory Neil Shapiro if (OpMode != MD_SMTP && 464605302a5SGregory Neil Shapiro OpMode != MD_DAEMON && 465605302a5SGregory Neil Shapiro OpMode != MD_ARPAFTP) 466605302a5SGregory Neil Shapiro { 4675ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 4685ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 469c2aa98e2SPeter Wemm *pbp++ = '\r'; 470c2aa98e2SPeter Wemm c = '.'; 471c2aa98e2SPeter Wemm } 472605302a5SGregory Neil Shapiro else 473605302a5SGregory Neil Shapiro c = '\r'; 474605302a5SGregory Neil Shapiro } 475c2aa98e2SPeter Wemm break; 476c2aa98e2SPeter Wemm 477c2aa98e2SPeter Wemm case IS_CR: 478c2aa98e2SPeter Wemm if (c == '\n') 479c2aa98e2SPeter Wemm istate = IS_BOL; 480c2aa98e2SPeter Wemm else 481c2aa98e2SPeter Wemm { 48240266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 48340266059SGregory Neil Shapiro c); 484c2aa98e2SPeter Wemm c = '\r'; 485c2aa98e2SPeter Wemm istate = IS_NORM; 486c2aa98e2SPeter Wemm } 487c2aa98e2SPeter Wemm goto bufferchar; 488c2aa98e2SPeter Wemm } 489c2aa98e2SPeter Wemm 490c2aa98e2SPeter Wemm if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 491c2aa98e2SPeter Wemm { 492c2aa98e2SPeter Wemm istate = IS_CR; 493c2aa98e2SPeter Wemm continue; 494c2aa98e2SPeter Wemm } 49540266059SGregory Neil Shapiro else if (c == '\n' && !bitset(EF_NL_NOT_EOL, 49640266059SGregory Neil Shapiro e->e_flags)) 497c2aa98e2SPeter Wemm istate = IS_BOL; 498c2aa98e2SPeter Wemm else 499c2aa98e2SPeter Wemm istate = IS_NORM; 500c2aa98e2SPeter Wemm 501c2aa98e2SPeter Wemm bufferchar: 502c2aa98e2SPeter Wemm if (!headeronly) 50342e5d165SGregory Neil Shapiro { 50442e5d165SGregory Neil Shapiro /* no overflow? */ 50542e5d165SGregory Neil Shapiro if (e->e_msgsize >= 0) 50642e5d165SGregory Neil Shapiro { 507c2aa98e2SPeter Wemm e->e_msgsize++; 50842e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 && 50942e5d165SGregory Neil Shapiro !bitset(EF_TOOBIG, e->e_flags) && 51042e5d165SGregory Neil Shapiro e->e_msgsize > MaxMessageSize) 51142e5d165SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 51242e5d165SGregory Neil Shapiro } 51342e5d165SGregory Neil Shapiro } 51425bab6e9SPeter Wemm switch (mstate) 515c2aa98e2SPeter Wemm { 51625bab6e9SPeter Wemm case MS_BODY: 517c2aa98e2SPeter Wemm /* just put the character out */ 51842e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 51940266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 52040266059SGregory Neil Shapiro c); 52140266059SGregory Neil Shapiro 52206f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 52325bab6e9SPeter Wemm 52425bab6e9SPeter Wemm case MS_DISCARD: 525c2aa98e2SPeter Wemm continue; 526c2aa98e2SPeter Wemm } 527c2aa98e2SPeter Wemm 528b6bacd31SGregory Neil Shapiro SM_ASSERT(mstate == MS_UFROM || mstate == MS_HEADER); 529b6bacd31SGregory Neil Shapiro 530c2aa98e2SPeter Wemm /* header -- buffer up */ 531c2aa98e2SPeter Wemm if (bp >= &buf[buflen - 2]) 532c2aa98e2SPeter Wemm { 533c2aa98e2SPeter Wemm char *obuf; 534c2aa98e2SPeter Wemm 535c2aa98e2SPeter Wemm /* out of space for header */ 536c2aa98e2SPeter Wemm obuf = buf; 537c2aa98e2SPeter Wemm if (buflen < MEMCHUNKSIZE) 538c2aa98e2SPeter Wemm buflen *= 2; 539c2aa98e2SPeter Wemm else 540c2aa98e2SPeter Wemm buflen += MEMCHUNKSIZE; 541c2aa98e2SPeter Wemm buf = xalloc(buflen); 54206f25ae9SGregory Neil Shapiro memmove(buf, obuf, bp - obuf); 543c2aa98e2SPeter Wemm bp = &buf[bp - obuf]; 544c2aa98e2SPeter Wemm if (obuf != bufbuf) 54540266059SGregory Neil Shapiro sm_free(obuf); /* XXX */ 546c2aa98e2SPeter Wemm } 54740266059SGregory Neil Shapiro 54840266059SGregory Neil Shapiro /* 54940266059SGregory Neil Shapiro ** XXX Notice: the logic here is broken. 55040266059SGregory Neil Shapiro ** An input to sendmail that doesn't contain a 55140266059SGregory Neil Shapiro ** header but starts immediately with the body whose 55240266059SGregory Neil Shapiro ** first line contain characters which match the 55340266059SGregory Neil Shapiro ** following "if" will cause problems: those 55440266059SGregory Neil Shapiro ** characters will NOT appear in the output... 55540266059SGregory Neil Shapiro ** Do we care? 55640266059SGregory Neil Shapiro */ 55740266059SGregory Neil Shapiro 558c2aa98e2SPeter Wemm if (c >= 0200 && c <= 0237) 559c2aa98e2SPeter Wemm { 56040266059SGregory Neil Shapiro #if 0 /* causes complaints -- figure out something for 8.n+1 */ 561c2aa98e2SPeter Wemm usrerr("Illegal character 0x%x in header", c); 56206f25ae9SGregory Neil Shapiro #else /* 0 */ 56306f25ae9SGregory Neil Shapiro /* EMPTY */ 56406f25ae9SGregory Neil Shapiro #endif /* 0 */ 565c2aa98e2SPeter Wemm } 566c2aa98e2SPeter Wemm else if (c != '\0') 56725bab6e9SPeter Wemm { 568c2aa98e2SPeter Wemm *bp++ = c; 56940266059SGregory Neil Shapiro ++hdrslen; 57013058a91SGregory Neil Shapiro if (!headeronly && 57113058a91SGregory Neil Shapiro MaxHeadersLength > 0 && 572602a2b1bSGregory Neil Shapiro hdrslen > MaxHeadersLength) 57325bab6e9SPeter Wemm { 57425bab6e9SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 5752e43090eSPeter Wemm "headers too large (%d max) from %s during message collect", 5762e43090eSPeter Wemm MaxHeadersLength, 57740266059SGregory Neil Shapiro CURHOSTNAME); 57825bab6e9SPeter Wemm errno = 0; 57925bab6e9SPeter Wemm e->e_flags |= EF_CLRQUEUE; 58025bab6e9SPeter Wemm e->e_status = "5.6.0"; 58106f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 58206f25ae9SGregory Neil Shapiro "552 Headers too large (%d max)", 5832e43090eSPeter Wemm MaxHeadersLength); 58425bab6e9SPeter Wemm mstate = MS_DISCARD; 58525bab6e9SPeter Wemm } 58625bab6e9SPeter Wemm } 587c2aa98e2SPeter Wemm if (istate == IS_BOL) 588c2aa98e2SPeter Wemm break; 589c2aa98e2SPeter Wemm } 590c2aa98e2SPeter Wemm *bp = '\0'; 591c2aa98e2SPeter Wemm 592c2aa98e2SPeter Wemm nextstate: 593c2aa98e2SPeter Wemm if (tTd(30, 35)) 59440266059SGregory Neil Shapiro sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 595c2aa98e2SPeter Wemm istate, mstate, buf); 596c2aa98e2SPeter Wemm switch (mstate) 597c2aa98e2SPeter Wemm { 598c2aa98e2SPeter Wemm case MS_UFROM: 599c2aa98e2SPeter Wemm mstate = MS_HEADER; 600c2aa98e2SPeter Wemm #ifndef NOTUNIX 601c2aa98e2SPeter Wemm if (strncmp(buf, "From ", 5) == 0) 602c2aa98e2SPeter Wemm { 603c2aa98e2SPeter Wemm bp = buf; 604c2aa98e2SPeter Wemm eatfrom(buf, e); 605c2aa98e2SPeter Wemm continue; 606c2aa98e2SPeter Wemm } 60706f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 60806f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 609c2aa98e2SPeter Wemm 610c2aa98e2SPeter Wemm case MS_HEADER: 611c2aa98e2SPeter Wemm if (!isheader(buf)) 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm mstate = MS_BODY; 614c2aa98e2SPeter Wemm goto nextstate; 615c2aa98e2SPeter Wemm } 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm /* check for possible continuation line */ 618c2aa98e2SPeter Wemm do 619c2aa98e2SPeter Wemm { 62040266059SGregory Neil Shapiro sm_io_clearerr(fp); 621c2aa98e2SPeter Wemm errno = 0; 62240266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 62340266059SGregory Neil Shapiro } while (c == SM_IO_EOF && errno == EINTR); 62440266059SGregory Neil Shapiro if (c != SM_IO_EOF) 62540266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 626c2aa98e2SPeter Wemm if (c == ' ' || c == '\t') 627c2aa98e2SPeter Wemm { 628c2aa98e2SPeter Wemm /* yep -- defer this */ 629c2aa98e2SPeter Wemm continue; 630c2aa98e2SPeter Wemm } 631c2aa98e2SPeter Wemm 632c2aa98e2SPeter Wemm /* trim off trailing CRLF or NL */ 6335ef517c0SGregory Neil Shapiro SM_ASSERT(bp > buf); 634c2aa98e2SPeter Wemm if (*--bp != '\n' || *--bp != '\r') 635c2aa98e2SPeter Wemm bp++; 636c2aa98e2SPeter Wemm *bp = '\0'; 63725bab6e9SPeter Wemm 63806f25ae9SGregory Neil Shapiro if (bitset(H_EOH, chompheader(buf, 63906f25ae9SGregory Neil Shapiro CHHDR_CHECK | CHHDR_USER, 64006f25ae9SGregory Neil Shapiro hdrp, e))) 641c2aa98e2SPeter Wemm { 642c2aa98e2SPeter Wemm mstate = MS_BODY; 643c2aa98e2SPeter Wemm goto nextstate; 644c2aa98e2SPeter Wemm } 64506f25ae9SGregory Neil Shapiro numhdrs++; 646c2aa98e2SPeter Wemm break; 647c2aa98e2SPeter Wemm 648c2aa98e2SPeter Wemm case MS_BODY: 649c2aa98e2SPeter Wemm if (tTd(30, 1)) 65040266059SGregory Neil Shapiro sm_dprintf("EOH\n"); 65106f25ae9SGregory Neil Shapiro 652c2aa98e2SPeter Wemm if (headeronly) 653c2aa98e2SPeter Wemm goto readerr; 65406f25ae9SGregory Neil Shapiro 65540266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 65640266059SGregory Neil Shapiro if (df == NULL) 65740266059SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 65806f25ae9SGregory Neil Shapiro 659c2aa98e2SPeter Wemm bp = buf; 660c2aa98e2SPeter Wemm 661c2aa98e2SPeter Wemm /* toss blank line */ 662c2aa98e2SPeter Wemm if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 663c2aa98e2SPeter Wemm bp[0] == '\r' && bp[1] == '\n') || 664c2aa98e2SPeter Wemm (!bitset(EF_NL_NOT_EOL, e->e_flags) && 665c2aa98e2SPeter Wemm bp[0] == '\n')) 666c2aa98e2SPeter Wemm { 667c2aa98e2SPeter Wemm break; 668c2aa98e2SPeter Wemm } 669c2aa98e2SPeter Wemm 670c2aa98e2SPeter Wemm /* if not a blank separator, write it out */ 67142e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 672c2aa98e2SPeter Wemm { 673c2aa98e2SPeter Wemm while (*bp != '\0') 67440266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 67540266059SGregory Neil Shapiro *bp++); 676c2aa98e2SPeter Wemm } 677c2aa98e2SPeter Wemm break; 678c2aa98e2SPeter Wemm } 679c2aa98e2SPeter Wemm bp = buf; 680c2aa98e2SPeter Wemm } 681c2aa98e2SPeter Wemm 682c2aa98e2SPeter Wemm readerr: 68340266059SGregory Neil Shapiro if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 684c2aa98e2SPeter Wemm { 68540266059SGregory Neil Shapiro const char *errmsg; 686c2aa98e2SPeter Wemm 68740266059SGregory Neil Shapiro if (sm_io_eof(fp)) 68840266059SGregory Neil Shapiro errmsg = "unexpected close"; 68940266059SGregory Neil Shapiro else 69040266059SGregory Neil Shapiro errmsg = sm_errstring(errno); 691c2aa98e2SPeter Wemm if (tTd(30, 1)) 69240266059SGregory Neil Shapiro sm_dprintf("collect: premature EOM: %s\n", errmsg); 69340266059SGregory Neil Shapiro if (LogLevel > 1) 694c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 695c2aa98e2SPeter Wemm "collect: premature EOM: %s", errmsg); 69640266059SGregory Neil Shapiro inputerr = true; 697c2aa98e2SPeter Wemm } 698c2aa98e2SPeter Wemm 699c2aa98e2SPeter Wemm /* reset global timer */ 7008774250cSGregory Neil Shapiro if (CollectTimeout != NULL) 70140266059SGregory Neil Shapiro sm_clrevent(CollectTimeout); 702c2aa98e2SPeter Wemm 703c2aa98e2SPeter Wemm if (headeronly) 704c2aa98e2SPeter Wemm return; 705c2aa98e2SPeter Wemm 70640266059SGregory Neil Shapiro if (mstate != MS_BODY) 70740266059SGregory Neil Shapiro { 70840266059SGregory Neil Shapiro /* no body or discard, so we never opened the data file */ 70940266059SGregory Neil Shapiro SM_ASSERT(df == NULL); 71040266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 71140266059SGregory Neil Shapiro } 71240266059SGregory Neil Shapiro 71306f25ae9SGregory Neil Shapiro if (df == NULL) 714c2aa98e2SPeter Wemm { 71506f25ae9SGregory Neil Shapiro /* skip next few clauses */ 71606f25ae9SGregory Neil Shapiro /* EMPTY */ 71706f25ae9SGregory Neil Shapiro } 71840266059SGregory Neil Shapiro else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 71906f25ae9SGregory Neil Shapiro { 72040266059SGregory Neil Shapiro dferror(df, "sm_io_flush||sm_io_error", e); 72140266059SGregory Neil Shapiro flush_errors(true); 72240266059SGregory Neil Shapiro finis(true, true, ExitStat); 72306f25ae9SGregory Neil Shapiro /* NOTREACHED */ 72406f25ae9SGregory Neil Shapiro } 725e92d3f3fSGregory Neil Shapiro else if (SuperSafe == SAFE_NO || 726e92d3f3fSGregory Neil Shapiro SuperSafe == SAFE_INTERACTIVE || 727e92d3f3fSGregory Neil Shapiro (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode)) 72806f25ae9SGregory Neil Shapiro { 72906f25ae9SGregory Neil Shapiro /* skip next few clauses */ 73006f25ae9SGregory Neil Shapiro /* EMPTY */ 73106f25ae9SGregory Neil Shapiro } 73240266059SGregory Neil Shapiro else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) 73306f25ae9SGregory Neil Shapiro { 73406f25ae9SGregory Neil Shapiro int save_errno = errno; 73506f25ae9SGregory Neil Shapiro 73606f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 73706f25ae9SGregory Neil Shapiro { 73806f25ae9SGregory Neil Shapiro char *dfile; 73906f25ae9SGregory Neil Shapiro struct stat st; 74040266059SGregory Neil Shapiro int dfd; 74106f25ae9SGregory Neil Shapiro 74240266059SGregory Neil Shapiro dfile = queuename(e, DATAFL_LETTER); 74306f25ae9SGregory Neil Shapiro if (stat(dfile, &st) < 0) 74406f25ae9SGregory Neil Shapiro st.st_size = -1; 74506f25ae9SGregory Neil Shapiro errno = EEXIST; 74640266059SGregory Neil Shapiro syserr("@collect: bfcommit(%s): already on disk, size=%ld", 74742e5d165SGregory Neil Shapiro dfile, (long) st.st_size); 74840266059SGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 74906f25ae9SGregory Neil Shapiro if (dfd >= 0) 75040266059SGregory Neil Shapiro dumpfd(dfd, true, true); 75106f25ae9SGregory Neil Shapiro } 75206f25ae9SGregory Neil Shapiro errno = save_errno; 75306f25ae9SGregory Neil Shapiro dferror(df, "bfcommit", e); 75440266059SGregory Neil Shapiro flush_errors(true); 75540266059SGregory Neil Shapiro finis(save_errno != EEXIST, true, ExitStat); 75606f25ae9SGregory Neil Shapiro } 757e92d3f3fSGregory Neil Shapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) 758e92d3f3fSGregory Neil Shapiro { 759e92d3f3fSGregory Neil Shapiro dferror(df, "sm_io_getinfo", e); 760e92d3f3fSGregory Neil Shapiro flush_errors(true); 761e92d3f3fSGregory Neil Shapiro finis(true, true, ExitStat); 762e92d3f3fSGregory Neil Shapiro /* NOTREACHED */ 763e92d3f3fSGregory Neil Shapiro } 764e92d3f3fSGregory Neil Shapiro else if (fsync(afd) < 0) 765602a2b1bSGregory Neil Shapiro { 76640266059SGregory Neil Shapiro dferror(df, "fsync", e); 76740266059SGregory Neil Shapiro flush_errors(true); 76840266059SGregory Neil Shapiro finis(true, true, ExitStat); 769602a2b1bSGregory Neil Shapiro /* NOTREACHED */ 770602a2b1bSGregory Neil Shapiro } 77140266059SGregory Neil Shapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 77206f25ae9SGregory Neil Shapiro { 77340266059SGregory Neil Shapiro dferror(df, "sm_io_close", e); 77440266059SGregory Neil Shapiro flush_errors(true); 77540266059SGregory Neil Shapiro finis(true, true, ExitStat); 77606f25ae9SGregory Neil Shapiro /* NOTREACHED */ 77706f25ae9SGregory Neil Shapiro } 77806f25ae9SGregory Neil Shapiro else 77906f25ae9SGregory Neil Shapiro { 78006f25ae9SGregory Neil Shapiro /* everything is happily flushed to disk */ 78106f25ae9SGregory Neil Shapiro df = NULL; 78240266059SGregory Neil Shapiro 78340266059SGregory Neil Shapiro /* remove from available space in filesystem */ 78440266059SGregory Neil Shapiro updfs(e, false, true); 785c2aa98e2SPeter Wemm } 786c2aa98e2SPeter Wemm 787c2aa98e2SPeter Wemm /* An EOF when running SMTP is an error */ 788c2aa98e2SPeter Wemm if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 789c2aa98e2SPeter Wemm { 790c2aa98e2SPeter Wemm char *host; 791c2aa98e2SPeter Wemm char *problem; 792959366dcSGregory Neil Shapiro ADDRESS *q; 793c2aa98e2SPeter Wemm 794c2aa98e2SPeter Wemm host = RealHostName; 795c2aa98e2SPeter Wemm if (host == NULL) 796c2aa98e2SPeter Wemm host = "localhost"; 797c2aa98e2SPeter Wemm 79840266059SGregory Neil Shapiro if (sm_io_eof(fp)) 799c2aa98e2SPeter Wemm problem = "unexpected close"; 80040266059SGregory Neil Shapiro else if (sm_io_error(fp)) 801c2aa98e2SPeter Wemm problem = "I/O error"; 802c2aa98e2SPeter Wemm else 803c2aa98e2SPeter Wemm problem = "read timeout"; 80440266059SGregory Neil Shapiro if (LogLevel > 0 && sm_io_eof(fp)) 805c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 80640266059SGregory Neil Shapiro "collect: %s on connection from %.100s, sender=%s", 807c2aa98e2SPeter Wemm problem, host, 80840266059SGregory Neil Shapiro shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 80940266059SGregory Neil Shapiro if (sm_io_eof(fp)) 81006f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 811c2aa98e2SPeter Wemm problem, host, 812c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 813c2aa98e2SPeter Wemm else 81406f25ae9SGregory Neil Shapiro syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 815c2aa98e2SPeter Wemm problem, host, 816c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 817c2aa98e2SPeter Wemm 818c2aa98e2SPeter Wemm /* don't return an error indication */ 819c2aa98e2SPeter Wemm e->e_to = NULL; 820c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 821c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 822c2aa98e2SPeter Wemm 823959366dcSGregory Neil Shapiro /* Don't send any message notification to sender */ 824959366dcSGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 825959366dcSGregory Neil Shapiro { 826959366dcSGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 827959366dcSGregory Neil Shapiro continue; 828959366dcSGregory Neil Shapiro q->q_state = QS_FATALERR; 829959366dcSGregory Neil Shapiro } 830959366dcSGregory Neil Shapiro 83140266059SGregory Neil Shapiro finis(true, true, ExitStat); 83206f25ae9SGregory Neil Shapiro /* NOTREACHED */ 833c2aa98e2SPeter Wemm } 834c2aa98e2SPeter Wemm 83540266059SGregory Neil Shapiro /* Log collection information. */ 83640266059SGregory Neil Shapiro if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 837c2aa98e2SPeter Wemm { 83840266059SGregory Neil Shapiro logsender(e, e->e_msgid); 83940266059SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER; 840c2aa98e2SPeter Wemm } 841c2aa98e2SPeter Wemm 842c2aa98e2SPeter Wemm /* check for message too large */ 84342e5d165SGregory Neil Shapiro if (bitset(EF_TOOBIG, e->e_flags)) 844c2aa98e2SPeter Wemm { 845c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 84640266059SGregory Neil Shapiro if (!bitset(EF_FATALERRS, e->e_flags)) 84740266059SGregory Neil Shapiro { 848c2aa98e2SPeter Wemm e->e_status = "5.2.3"; 84906f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 85006f25ae9SGregory Neil Shapiro "552 Message exceeds maximum fixed size (%ld)", 851c2aa98e2SPeter Wemm MaxMessageSize); 852c2aa98e2SPeter Wemm if (LogLevel > 6) 853c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 854c2aa98e2SPeter Wemm "message size (%ld) exceeds maximum (%ld)", 855c2aa98e2SPeter Wemm e->e_msgsize, MaxMessageSize); 856c2aa98e2SPeter Wemm } 85740266059SGregory Neil Shapiro } 858c2aa98e2SPeter Wemm 859c2aa98e2SPeter Wemm /* check for illegal 8-bit data */ 860c2aa98e2SPeter Wemm if (HasEightBits) 861c2aa98e2SPeter Wemm { 862c2aa98e2SPeter Wemm e->e_flags |= EF_HAS8BIT; 863c2aa98e2SPeter Wemm if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 864c2aa98e2SPeter Wemm !bitset(EF_IS_MIME, e->e_flags)) 865c2aa98e2SPeter Wemm { 866c2aa98e2SPeter Wemm e->e_status = "5.6.1"; 86706f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 868c2aa98e2SPeter Wemm } 869c2aa98e2SPeter Wemm } 870c2aa98e2SPeter Wemm else 871c2aa98e2SPeter Wemm { 872c2aa98e2SPeter Wemm /* if it claimed to be 8 bits, well, it lied.... */ 873c2aa98e2SPeter Wemm if (e->e_bodytype != NULL && 87440266059SGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 875c2aa98e2SPeter Wemm e->e_bodytype = "7BIT"; 876c2aa98e2SPeter Wemm } 877c2aa98e2SPeter Wemm 87840266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 87906f25ae9SGregory Neil Shapiro { 88040266059SGregory Neil Shapiro char *dfname = queuename(e, DATAFL_LETTER); 88140266059SGregory Neil Shapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 882e92d3f3fSGregory Neil Shapiro SM_IO_RDONLY_B, NULL)) == NULL) 883c2aa98e2SPeter Wemm { 884c2aa98e2SPeter Wemm /* we haven't acked receipt yet, so just chuck this */ 88540266059SGregory Neil Shapiro syserr("@Cannot reopen %s", dfname); 88640266059SGregory Neil Shapiro finis(true, true, ExitStat); 88706f25ae9SGregory Neil Shapiro /* NOTREACHED */ 888c2aa98e2SPeter Wemm } 889c2aa98e2SPeter Wemm } 89006f25ae9SGregory Neil Shapiro else 89106f25ae9SGregory Neil Shapiro e->e_dfp = df; 892605302a5SGregory Neil Shapiro 893605302a5SGregory Neil Shapiro /* collect statistics */ 894605302a5SGregory Neil Shapiro if (OpMode != MD_VERIFY) 895a7ec597cSGregory Neil Shapiro { 896a7ec597cSGregory Neil Shapiro /* 897a7ec597cSGregory Neil Shapiro ** Recalculate e_msgpriority, it is done at in eatheader() 898a7ec597cSGregory Neil Shapiro ** which is called (in 8.12) after the header is collected, 899a7ec597cSGregory Neil Shapiro ** hence e_msgsize is (most likely) incorrect. 900a7ec597cSGregory Neil Shapiro */ 901a7ec597cSGregory Neil Shapiro 902a7ec597cSGregory Neil Shapiro e->e_msgpriority = e->e_msgsize 903a7ec597cSGregory Neil Shapiro - e->e_class * WkClassFact 904a7ec597cSGregory Neil Shapiro + e->e_nrcpts * WkRecipFact; 905605302a5SGregory Neil Shapiro markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 90606f25ae9SGregory Neil Shapiro } 907a7ec597cSGregory Neil Shapiro } 908c2aa98e2SPeter Wemm 909c2aa98e2SPeter Wemm static void 910c2aa98e2SPeter Wemm collecttimeout(timeout) 911b6bacd31SGregory Neil Shapiro int timeout; 912c2aa98e2SPeter Wemm { 9138774250cSGregory Neil Shapiro int save_errno = errno; 914c2aa98e2SPeter Wemm 9158774250cSGregory Neil Shapiro /* 9168774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 9178774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 9188774250cSGregory Neil Shapiro ** DOING. 9198774250cSGregory Neil Shapiro */ 9208774250cSGregory Neil Shapiro 9218774250cSGregory Neil Shapiro if (CollectProgress) 9228774250cSGregory Neil Shapiro { 9238774250cSGregory Neil Shapiro /* reset the timeout */ 92440266059SGregory Neil Shapiro CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout, 9258774250cSGregory Neil Shapiro timeout); 92640266059SGregory Neil Shapiro CollectProgress = false; 927c2aa98e2SPeter Wemm } 9288774250cSGregory Neil Shapiro else 9298774250cSGregory Neil Shapiro { 9308774250cSGregory Neil Shapiro /* event is done */ 9318774250cSGregory Neil Shapiro CollectTimeout = NULL; 9328774250cSGregory Neil Shapiro } 9338774250cSGregory Neil Shapiro 9348774250cSGregory Neil Shapiro /* if no progress was made or problem resetting event, die now */ 9358774250cSGregory Neil Shapiro if (CollectTimeout == NULL) 9368774250cSGregory Neil Shapiro { 9378774250cSGregory Neil Shapiro errno = ETIMEDOUT; 9388774250cSGregory Neil Shapiro longjmp(CtxCollectTimeout, 1); 9398774250cSGregory Neil Shapiro } 9408774250cSGregory Neil Shapiro errno = save_errno; 9418774250cSGregory Neil Shapiro } 94240266059SGregory Neil Shapiro /* 94306f25ae9SGregory Neil Shapiro ** DFERROR -- signal error on writing the data file. 944c2aa98e2SPeter Wemm ** 94540266059SGregory Neil Shapiro ** Called by collect(). Collect() always terminates the process 94640266059SGregory Neil Shapiro ** immediately after calling dferror(), which means that the SMTP 94740266059SGregory Neil Shapiro ** session will be terminated, which means that any error message 94840266059SGregory Neil Shapiro ** issued by dferror must be a 421 error, as per RFC 821. 94940266059SGregory Neil Shapiro ** 950c2aa98e2SPeter Wemm ** Parameters: 95106f25ae9SGregory Neil Shapiro ** df -- the file pointer for the data file. 95206f25ae9SGregory Neil Shapiro ** msg -- detailed message. 953c2aa98e2SPeter Wemm ** e -- the current envelope. 954c2aa98e2SPeter Wemm ** 955c2aa98e2SPeter Wemm ** Returns: 956c2aa98e2SPeter Wemm ** none. 957c2aa98e2SPeter Wemm ** 958c2aa98e2SPeter Wemm ** Side Effects: 959c2aa98e2SPeter Wemm ** Gives an error message. 960c2aa98e2SPeter Wemm ** Arranges for following output to go elsewhere. 961c2aa98e2SPeter Wemm */ 962c2aa98e2SPeter Wemm 963e92d3f3fSGregory Neil Shapiro void 96406f25ae9SGregory Neil Shapiro dferror(df, msg, e) 96540266059SGregory Neil Shapiro SM_FILE_T *volatile df; 96606f25ae9SGregory Neil Shapiro char *msg; 967c2aa98e2SPeter Wemm register ENVELOPE *e; 968c2aa98e2SPeter Wemm { 96906f25ae9SGregory Neil Shapiro char *dfname; 97006f25ae9SGregory Neil Shapiro 97140266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 972c2aa98e2SPeter Wemm setstat(EX_IOERR); 973c2aa98e2SPeter Wemm if (errno == ENOSPC) 974c2aa98e2SPeter Wemm { 975c2aa98e2SPeter Wemm #if STAT64 > 0 976c2aa98e2SPeter Wemm struct stat64 st; 97706f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 978c2aa98e2SPeter Wemm struct stat st; 97906f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 980c2aa98e2SPeter Wemm long avail; 981c2aa98e2SPeter Wemm long bsize; 982c2aa98e2SPeter Wemm 983c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 984c2aa98e2SPeter Wemm 985c2aa98e2SPeter Wemm if ( 986c2aa98e2SPeter Wemm #if STAT64 > 0 98740266059SGregory Neil Shapiro fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 98806f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 98940266059SGregory Neil Shapiro fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 99006f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 991c2aa98e2SPeter Wemm < 0) 992c2aa98e2SPeter Wemm st.st_size = 0; 99340266059SGregory Neil Shapiro (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 994e92d3f3fSGregory Neil Shapiro SM_IO_WRONLY_B, NULL, df); 995c2aa98e2SPeter Wemm if (st.st_size <= 0) 99640266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 99740266059SGregory Neil Shapiro "\n*** Mail could not be accepted"); 998c2aa98e2SPeter Wemm else 99940266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 100040266059SGregory Neil Shapiro "\n*** Mail of at least %llu bytes could not be accepted\n", 100140266059SGregory Neil Shapiro (ULONGLONG_T) st.st_size); 100240266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 100340266059SGregory Neil Shapiro "*** at %s due to lack of disk space for temp file.\n", 1004c2aa98e2SPeter Wemm MyHostName); 100540266059SGregory Neil Shapiro avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 100640266059SGregory Neil Shapiro &bsize); 1007c2aa98e2SPeter Wemm if (avail > 0) 1008c2aa98e2SPeter Wemm { 1009c2aa98e2SPeter Wemm if (bsize > 1024) 1010c2aa98e2SPeter Wemm avail *= bsize / 1024; 1011c2aa98e2SPeter Wemm else if (bsize < 1024) 1012c2aa98e2SPeter Wemm avail /= 1024 / bsize; 101340266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 101440266059SGregory Neil Shapiro "*** Currently, %ld kilobytes are available for mail temp files.\n", 1015c2aa98e2SPeter Wemm avail); 1016c2aa98e2SPeter Wemm } 101740266059SGregory Neil Shapiro #if 0 101840266059SGregory Neil Shapiro /* Wrong response code; should be 421. */ 1019c2aa98e2SPeter Wemm e->e_status = "4.3.1"; 102006f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 102140266059SGregory Neil Shapiro #else /* 0 */ 102240266059SGregory Neil Shapiro syserr("421 4.3.1 Out of disk space for temp file"); 102340266059SGregory Neil Shapiro #endif /* 0 */ 1024c2aa98e2SPeter Wemm } 1025c2aa98e2SPeter Wemm else 102640266059SGregory Neil Shapiro syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", 102794c01205SGregory Neil Shapiro dfname, msg, (int) geteuid(), (int) getegid()); 102840266059SGregory Neil Shapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 102940266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df) == NULL) 1030c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 103140266059SGregory Neil Shapiro "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 103240266059SGregory Neil Shapiro sm_errstring(errno)); 1033c2aa98e2SPeter Wemm } 103440266059SGregory Neil Shapiro /* 1035c2aa98e2SPeter Wemm ** EATFROM -- chew up a UNIX style from line and process 1036c2aa98e2SPeter Wemm ** 1037c2aa98e2SPeter Wemm ** This does indeed make some assumptions about the format 1038c2aa98e2SPeter Wemm ** of UNIX messages. 1039c2aa98e2SPeter Wemm ** 1040c2aa98e2SPeter Wemm ** Parameters: 1041c2aa98e2SPeter Wemm ** fm -- the from line. 1042a7ec597cSGregory Neil Shapiro ** e -- envelope 1043c2aa98e2SPeter Wemm ** 1044c2aa98e2SPeter Wemm ** Returns: 1045c2aa98e2SPeter Wemm ** none. 1046c2aa98e2SPeter Wemm ** 1047c2aa98e2SPeter Wemm ** Side Effects: 1048c2aa98e2SPeter Wemm ** extracts what information it can from the header, 1049c2aa98e2SPeter Wemm ** such as the date. 1050c2aa98e2SPeter Wemm */ 1051c2aa98e2SPeter Wemm 1052c2aa98e2SPeter Wemm #ifndef NOTUNIX 1053c2aa98e2SPeter Wemm 105406f25ae9SGregory Neil Shapiro static char *DowList[] = 1055c2aa98e2SPeter Wemm { 1056c2aa98e2SPeter Wemm "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 1057c2aa98e2SPeter Wemm }; 1058c2aa98e2SPeter Wemm 105906f25ae9SGregory Neil Shapiro static char *MonthList[] = 1060c2aa98e2SPeter Wemm { 1061c2aa98e2SPeter Wemm "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1062c2aa98e2SPeter Wemm "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 1063c2aa98e2SPeter Wemm NULL 1064c2aa98e2SPeter Wemm }; 1065c2aa98e2SPeter Wemm 106606f25ae9SGregory Neil Shapiro static void 1067c2aa98e2SPeter Wemm eatfrom(fm, e) 1068c2aa98e2SPeter Wemm char *volatile fm; 1069c2aa98e2SPeter Wemm register ENVELOPE *e; 1070c2aa98e2SPeter Wemm { 1071c2aa98e2SPeter Wemm register char *p; 1072c2aa98e2SPeter Wemm register char **dt; 1073c2aa98e2SPeter Wemm 1074c2aa98e2SPeter Wemm if (tTd(30, 2)) 107540266059SGregory Neil Shapiro sm_dprintf("eatfrom(%s)\n", fm); 1076c2aa98e2SPeter Wemm 1077c2aa98e2SPeter Wemm /* find the date part */ 1078c2aa98e2SPeter Wemm p = fm; 1079c2aa98e2SPeter Wemm while (*p != '\0') 1080c2aa98e2SPeter Wemm { 1081c2aa98e2SPeter Wemm /* skip a word */ 1082c2aa98e2SPeter Wemm while (*p != '\0' && *p != ' ') 1083c2aa98e2SPeter Wemm p++; 1084c2aa98e2SPeter Wemm while (*p == ' ') 1085c2aa98e2SPeter Wemm p++; 1086193538b7SGregory Neil Shapiro if (strlen(p) < 17) 1087193538b7SGregory Neil Shapiro { 1088193538b7SGregory Neil Shapiro /* no room for the date */ 1089193538b7SGregory Neil Shapiro return; 1090193538b7SGregory Neil Shapiro } 1091c2aa98e2SPeter Wemm if (!(isascii(*p) && isupper(*p)) || 1092c2aa98e2SPeter Wemm p[3] != ' ' || p[13] != ':' || p[16] != ':') 1093c2aa98e2SPeter Wemm continue; 1094c2aa98e2SPeter Wemm 1095c2aa98e2SPeter Wemm /* we have a possible date */ 1096c2aa98e2SPeter Wemm for (dt = DowList; *dt != NULL; dt++) 1097c2aa98e2SPeter Wemm if (strncmp(*dt, p, 3) == 0) 1098c2aa98e2SPeter Wemm break; 1099c2aa98e2SPeter Wemm if (*dt == NULL) 1100c2aa98e2SPeter Wemm continue; 1101c2aa98e2SPeter Wemm 1102c2aa98e2SPeter Wemm for (dt = MonthList; *dt != NULL; dt++) 1103193538b7SGregory Neil Shapiro { 1104c2aa98e2SPeter Wemm if (strncmp(*dt, &p[4], 3) == 0) 1105c2aa98e2SPeter Wemm break; 1106193538b7SGregory Neil Shapiro } 1107c2aa98e2SPeter Wemm if (*dt != NULL) 1108c2aa98e2SPeter Wemm break; 1109c2aa98e2SPeter Wemm } 1110c2aa98e2SPeter Wemm 1111c2aa98e2SPeter Wemm if (*p != '\0') 1112c2aa98e2SPeter Wemm { 111340266059SGregory Neil Shapiro char *q, buf[25]; 1114c2aa98e2SPeter Wemm 1115c2aa98e2SPeter Wemm /* we have found a date */ 111640266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p, sizeof(buf)); 111740266059SGregory Neil Shapiro q = arpadate(buf); 111840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'a', q); 1119c2aa98e2SPeter Wemm } 1120c2aa98e2SPeter Wemm } 112106f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 1122