1c2aa98e2SPeter Wemm /* 2a7ec597cSGregory Neil Shapiro * Copyright (c) 1998-2003 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 16a7ec597cSGregory Neil Shapiro SM_RCSID("@(#)$Id: collect.c,v 8.242.2.8 2003/07/08 01:16:35 ca Exp $") 1706f25ae9SGregory Neil Shapiro 1806f25ae9SGregory Neil Shapiro static void collecttimeout __P((time_t)); 1940266059SGregory Neil Shapiro static void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *)); 2006f25ae9SGregory Neil Shapiro static void eatfrom __P((char *volatile, ENVELOPE *)); 2140266059SGregory Neil Shapiro static void collect_doheader __P((ENVELOPE *)); 2240266059SGregory Neil Shapiro static SM_FILE_T *collect_dfopen __P((ENVELOPE *)); 2340266059SGregory Neil Shapiro static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int)); 2406f25ae9SGregory Neil Shapiro 2540266059SGregory Neil Shapiro /* 2640266059SGregory Neil Shapiro ** COLLECT_EOH -- end-of-header processing in collect() 2740266059SGregory Neil Shapiro ** 2840266059SGregory Neil Shapiro ** Called by collect() when it encounters the blank line 2940266059SGregory Neil Shapiro ** separating the header from the message body, or when it 3040266059SGregory Neil Shapiro ** encounters EOF in a message that contains only a header. 3140266059SGregory Neil Shapiro ** 3240266059SGregory Neil Shapiro ** Parameters: 3340266059SGregory Neil Shapiro ** e -- envelope 3440266059SGregory Neil Shapiro ** numhdrs -- number of headers 3540266059SGregory Neil Shapiro ** hdrslen -- length of headers 3640266059SGregory Neil Shapiro ** 3740266059SGregory Neil Shapiro ** Results: 3840266059SGregory Neil Shapiro ** NULL, or handle to open data file 3940266059SGregory Neil Shapiro ** 4040266059SGregory Neil Shapiro ** Side Effects: 4140266059SGregory Neil Shapiro ** end-of-header check ruleset is invoked. 4240266059SGregory Neil Shapiro ** envelope state is updated. 4340266059SGregory Neil Shapiro ** headers may be added and deleted. 4440266059SGregory Neil Shapiro ** selects the queue. 4540266059SGregory Neil Shapiro ** opens the data file. 4640266059SGregory Neil Shapiro */ 4740266059SGregory Neil Shapiro 4840266059SGregory Neil Shapiro static SM_FILE_T * 4940266059SGregory Neil Shapiro collect_eoh(e, numhdrs, hdrslen) 5040266059SGregory Neil Shapiro ENVELOPE *e; 5140266059SGregory Neil Shapiro int numhdrs; 5240266059SGregory Neil Shapiro int hdrslen; 5340266059SGregory Neil Shapiro { 5440266059SGregory Neil Shapiro char hnum[16]; 5540266059SGregory Neil Shapiro char hsize[16]; 5640266059SGregory Neil Shapiro 5740266059SGregory Neil Shapiro /* call the end-of-header check ruleset */ 5840266059SGregory Neil Shapiro (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs); 5940266059SGregory Neil Shapiro (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen); 6040266059SGregory Neil Shapiro if (tTd(30, 10)) 6140266059SGregory Neil Shapiro sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 6240266059SGregory Neil Shapiro hnum, hsize); 63959366dcSGregory Neil Shapiro (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT, 64959366dcSGregory Neil Shapiro 3, NULL, e->e_id); 6540266059SGregory Neil Shapiro 6640266059SGregory Neil Shapiro /* 6740266059SGregory Neil Shapiro ** Process the header, 6840266059SGregory Neil Shapiro ** select the queue, open the data file. 6940266059SGregory Neil Shapiro */ 7040266059SGregory Neil Shapiro 7140266059SGregory Neil Shapiro collect_doheader(e); 7240266059SGregory Neil Shapiro return collect_dfopen(e); 7340266059SGregory Neil Shapiro } 7440266059SGregory Neil Shapiro 7540266059SGregory Neil Shapiro /* 7640266059SGregory Neil Shapiro ** COLLECT_DOHEADER -- process header in collect() 7740266059SGregory Neil Shapiro ** 7840266059SGregory Neil Shapiro ** Called by collect() after it has finished parsing the header, 7940266059SGregory Neil Shapiro ** but before it selects the queue and creates the data file. 8040266059SGregory Neil Shapiro ** The results of processing the header will affect queue selection. 8140266059SGregory Neil Shapiro ** 8240266059SGregory Neil Shapiro ** Parameters: 8340266059SGregory Neil Shapiro ** e -- envelope 8440266059SGregory Neil Shapiro ** 8540266059SGregory Neil Shapiro ** Results: 8640266059SGregory Neil Shapiro ** none. 8740266059SGregory Neil Shapiro ** 8840266059SGregory Neil Shapiro ** Side Effects: 8940266059SGregory Neil Shapiro ** envelope state is updated. 9040266059SGregory Neil Shapiro ** headers may be added and deleted. 9140266059SGregory Neil Shapiro */ 9240266059SGregory Neil Shapiro 9340266059SGregory Neil Shapiro static void 9440266059SGregory Neil Shapiro collect_doheader(e) 9540266059SGregory Neil Shapiro ENVELOPE *e; 9640266059SGregory Neil Shapiro { 9740266059SGregory Neil Shapiro /* 9840266059SGregory Neil Shapiro ** Find out some information from the headers. 9940266059SGregory Neil Shapiro ** Examples are who is the from person & the date. 10040266059SGregory Neil Shapiro */ 10140266059SGregory Neil Shapiro 10240266059SGregory Neil Shapiro eatheader(e, true, false); 10340266059SGregory Neil Shapiro 10440266059SGregory Neil Shapiro if (GrabTo && e->e_sendqueue == NULL) 10540266059SGregory Neil Shapiro usrerr("No recipient addresses found in header"); 10640266059SGregory Neil Shapiro 10740266059SGregory Neil Shapiro /* 10840266059SGregory Neil Shapiro ** If we have a Return-Receipt-To:, turn it into a DSN. 10940266059SGregory Neil Shapiro */ 11040266059SGregory Neil Shapiro 11140266059SGregory Neil Shapiro if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 11240266059SGregory Neil Shapiro { 11340266059SGregory Neil Shapiro ADDRESS *q; 11440266059SGregory Neil Shapiro 11540266059SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 11640266059SGregory Neil Shapiro if (!bitset(QHASNOTIFY, q->q_flags)) 11740266059SGregory Neil Shapiro q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 11840266059SGregory Neil Shapiro } 11940266059SGregory Neil Shapiro 12040266059SGregory Neil Shapiro /* 12140266059SGregory Neil Shapiro ** Add an appropriate recipient line if we have none. 12240266059SGregory Neil Shapiro */ 12340266059SGregory Neil Shapiro 12440266059SGregory Neil Shapiro if (hvalue("to", e->e_header) != NULL || 12540266059SGregory Neil Shapiro hvalue("cc", e->e_header) != NULL || 12640266059SGregory Neil Shapiro hvalue("apparently-to", e->e_header) != NULL) 12740266059SGregory Neil Shapiro { 12840266059SGregory Neil Shapiro /* have a valid recipient header -- delete Bcc: headers */ 12940266059SGregory Neil Shapiro e->e_flags |= EF_DELETE_BCC; 13040266059SGregory Neil Shapiro } 13140266059SGregory Neil Shapiro else if (hvalue("bcc", e->e_header) == NULL) 13240266059SGregory Neil Shapiro { 13340266059SGregory Neil Shapiro /* no valid recipient headers */ 13440266059SGregory Neil Shapiro register ADDRESS *q; 13540266059SGregory Neil Shapiro char *hdr = NULL; 13640266059SGregory Neil Shapiro 13740266059SGregory Neil Shapiro /* create a recipient field */ 13840266059SGregory Neil Shapiro switch (NoRecipientAction) 13940266059SGregory Neil Shapiro { 14040266059SGregory Neil Shapiro case NRA_ADD_APPARENTLY_TO: 14140266059SGregory Neil Shapiro hdr = "Apparently-To"; 14240266059SGregory Neil Shapiro break; 14340266059SGregory Neil Shapiro 14440266059SGregory Neil Shapiro case NRA_ADD_TO: 14540266059SGregory Neil Shapiro hdr = "To"; 14640266059SGregory Neil Shapiro break; 14740266059SGregory Neil Shapiro 14840266059SGregory Neil Shapiro case NRA_ADD_BCC: 14940266059SGregory Neil Shapiro addheader("Bcc", " ", 0, e); 15040266059SGregory Neil Shapiro break; 15140266059SGregory Neil Shapiro 15240266059SGregory Neil Shapiro case NRA_ADD_TO_UNDISCLOSED: 15340266059SGregory Neil Shapiro addheader("To", "undisclosed-recipients:;", 0, e); 15440266059SGregory Neil Shapiro break; 15540266059SGregory Neil Shapiro } 15640266059SGregory Neil Shapiro 15740266059SGregory Neil Shapiro if (hdr != NULL) 15840266059SGregory Neil Shapiro { 15940266059SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16040266059SGregory Neil Shapiro { 16140266059SGregory Neil Shapiro if (q->q_alias != NULL) 16240266059SGregory Neil Shapiro continue; 16340266059SGregory Neil Shapiro if (tTd(30, 3)) 16440266059SGregory Neil Shapiro sm_dprintf("Adding %s: %s\n", 16540266059SGregory Neil Shapiro hdr, q->q_paddr); 16640266059SGregory Neil Shapiro addheader(hdr, q->q_paddr, 0, e); 16740266059SGregory Neil Shapiro } 16840266059SGregory Neil Shapiro } 16940266059SGregory Neil Shapiro } 17040266059SGregory Neil Shapiro } 17140266059SGregory Neil Shapiro 17240266059SGregory Neil Shapiro /* 17340266059SGregory Neil Shapiro ** COLLECT_DFOPEN -- open the message data file 17440266059SGregory Neil Shapiro ** 17540266059SGregory Neil Shapiro ** Called by collect() after it has finished processing the header. 17640266059SGregory Neil Shapiro ** Queue selection occurs at this point, possibly based on the 17740266059SGregory Neil Shapiro ** envelope's recipient list and on header information. 17840266059SGregory Neil Shapiro ** 17940266059SGregory Neil Shapiro ** Parameters: 18040266059SGregory Neil Shapiro ** e -- envelope 18140266059SGregory Neil Shapiro ** 18240266059SGregory Neil Shapiro ** Results: 18340266059SGregory Neil Shapiro ** NULL, or a pointer to an open data file, 18440266059SGregory Neil Shapiro ** into which the message body will be written by collect(). 18540266059SGregory Neil Shapiro ** 18640266059SGregory Neil Shapiro ** Side Effects: 18740266059SGregory Neil Shapiro ** Calls syserr, sets EF_FATALERRS and returns NULL 18840266059SGregory Neil Shapiro ** if there is insufficient disk space. 18940266059SGregory Neil Shapiro ** Aborts process if data file could not be opened. 19040266059SGregory Neil Shapiro ** Otherwise, the queue is selected, 19140266059SGregory Neil Shapiro ** e->e_{dfino,dfdev,msgsize,flags} are updated, 19240266059SGregory Neil Shapiro ** and a pointer to an open data file is returned. 19340266059SGregory Neil Shapiro */ 19440266059SGregory Neil Shapiro 19540266059SGregory Neil Shapiro static SM_FILE_T * 19640266059SGregory Neil Shapiro collect_dfopen(e) 19740266059SGregory Neil Shapiro ENVELOPE *e; 19840266059SGregory Neil Shapiro { 19940266059SGregory Neil Shapiro MODE_T oldumask = 0; 20040266059SGregory Neil Shapiro int dfd; 20140266059SGregory Neil Shapiro struct stat stbuf; 20240266059SGregory Neil Shapiro SM_FILE_T *df; 20340266059SGregory Neil Shapiro char *dfname; 20440266059SGregory Neil Shapiro 20540266059SGregory Neil Shapiro if (!setnewqueue(e)) 20640266059SGregory Neil Shapiro return NULL; 20740266059SGregory Neil Shapiro 20840266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 20940266059SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 21040266059SGregory Neil Shapiro oldumask = umask(002); 21140266059SGregory Neil Shapiro df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 21240266059SGregory Neil Shapiro SFF_OPENASROOT); 21340266059SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 21440266059SGregory Neil Shapiro (void) umask(oldumask); 21540266059SGregory Neil Shapiro if (df == NULL) 21640266059SGregory Neil Shapiro { 21740266059SGregory Neil Shapiro syserr("@Cannot create %s", dfname); 21840266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 21940266059SGregory Neil Shapiro flush_errors(true); 220a7ec597cSGregory Neil Shapiro finis(false, true, ExitStat); 22140266059SGregory Neil Shapiro /* NOTREACHED */ 22240266059SGregory Neil Shapiro } 22340266059SGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 22440266059SGregory Neil Shapiro if (dfd < 0 || fstat(dfd, &stbuf) < 0) 22540266059SGregory Neil Shapiro e->e_dfino = -1; 22640266059SGregory Neil Shapiro else 22740266059SGregory Neil Shapiro { 22840266059SGregory Neil Shapiro e->e_dfdev = stbuf.st_dev; 22940266059SGregory Neil Shapiro e->e_dfino = stbuf.st_ino; 23040266059SGregory Neil Shapiro } 23140266059SGregory Neil Shapiro e->e_flags |= EF_HAS_DF; 23240266059SGregory Neil Shapiro return df; 23340266059SGregory Neil Shapiro } 23440266059SGregory Neil Shapiro 23540266059SGregory Neil Shapiro /* 236c2aa98e2SPeter Wemm ** COLLECT -- read & parse message header & make temp file. 237c2aa98e2SPeter Wemm ** 238c2aa98e2SPeter Wemm ** Creates a temporary file name and copies the standard 239c2aa98e2SPeter Wemm ** input to that file. Leading UNIX-style "From" lines are 240c2aa98e2SPeter Wemm ** stripped off (after important information is extracted). 241c2aa98e2SPeter Wemm ** 242c2aa98e2SPeter Wemm ** Parameters: 243c2aa98e2SPeter Wemm ** fp -- file to read. 244c2aa98e2SPeter Wemm ** smtpmode -- if set, we are running SMTP: give an RFC821 245c2aa98e2SPeter Wemm ** style message to say we are ready to collect 246c2aa98e2SPeter Wemm ** input, and never ignore a single dot to mean 247c2aa98e2SPeter Wemm ** end of message. 248c2aa98e2SPeter Wemm ** hdrp -- the location to stash the header. 249c2aa98e2SPeter Wemm ** e -- the current envelope. 250a7ec597cSGregory Neil Shapiro ** rsetsize -- reset e_msgsize? 251c2aa98e2SPeter Wemm ** 252c2aa98e2SPeter Wemm ** Returns: 253c2aa98e2SPeter Wemm ** none. 254c2aa98e2SPeter Wemm ** 255c2aa98e2SPeter Wemm ** Side Effects: 25640266059SGregory Neil Shapiro ** If successful, 25740266059SGregory Neil Shapiro ** - Data file is created and filled, and e->e_dfp is set. 25840266059SGregory Neil Shapiro ** - The from person may be set. 25940266059SGregory Neil Shapiro ** If the "enough disk space" check fails, 26040266059SGregory Neil Shapiro ** - syserr is called. 26140266059SGregory Neil Shapiro ** - e->e_dfp is NULL. 26240266059SGregory Neil Shapiro ** - e->e_flags & EF_FATALERRS is set. 26340266059SGregory Neil Shapiro ** - collect() returns. 26440266059SGregory Neil Shapiro ** If data file cannot be created, the process is terminated. 265c2aa98e2SPeter Wemm */ 266c2aa98e2SPeter Wemm 267c2aa98e2SPeter Wemm static jmp_buf CtxCollectTimeout; 2688774250cSGregory Neil Shapiro static bool volatile CollectProgress; 26940266059SGregory Neil Shapiro static SM_EVENT *volatile CollectTimeout = NULL; 270c2aa98e2SPeter Wemm 271c2aa98e2SPeter Wemm /* values for input state machine */ 272c2aa98e2SPeter Wemm #define IS_NORM 0 /* middle of line */ 273c2aa98e2SPeter Wemm #define IS_BOL 1 /* beginning of line */ 274c2aa98e2SPeter Wemm #define IS_DOT 2 /* read a dot at beginning of line */ 275c2aa98e2SPeter Wemm #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 276c2aa98e2SPeter Wemm #define IS_CR 4 /* read a carriage return */ 277c2aa98e2SPeter Wemm 278c2aa98e2SPeter Wemm /* values for message state machine */ 279c2aa98e2SPeter Wemm #define MS_UFROM 0 /* reading Unix from line */ 280c2aa98e2SPeter Wemm #define MS_HEADER 1 /* reading message header */ 281c2aa98e2SPeter Wemm #define MS_BODY 2 /* reading message body */ 28225bab6e9SPeter Wemm #define MS_DISCARD 3 /* discarding rest of message */ 283c2aa98e2SPeter Wemm 284c2aa98e2SPeter Wemm void 285a7ec597cSGregory Neil Shapiro collect(fp, smtpmode, hdrp, e, rsetsize) 28640266059SGregory Neil Shapiro SM_FILE_T *fp; 287c2aa98e2SPeter Wemm bool smtpmode; 288c2aa98e2SPeter Wemm HDR **hdrp; 289c2aa98e2SPeter Wemm register ENVELOPE *e; 290a7ec597cSGregory Neil Shapiro bool rsetsize; 291c2aa98e2SPeter Wemm { 29240266059SGregory Neil Shapiro register SM_FILE_T *volatile df; 29340266059SGregory Neil Shapiro volatile bool ignrdot; 29440266059SGregory Neil Shapiro volatile time_t dbto; 295c2aa98e2SPeter Wemm register char *volatile bp; 29640266059SGregory Neil Shapiro volatile int c; 29740266059SGregory Neil Shapiro volatile bool inputerr; 298c2aa98e2SPeter Wemm bool headeronly; 299c2aa98e2SPeter Wemm char *volatile buf; 300c2aa98e2SPeter Wemm volatile int buflen; 301c2aa98e2SPeter Wemm volatile int istate; 302c2aa98e2SPeter Wemm volatile int mstate; 30340266059SGregory Neil Shapiro volatile int hdrslen; 30440266059SGregory Neil Shapiro volatile int numhdrs; 30540266059SGregory Neil Shapiro volatile int afd; 30640266059SGregory Neil Shapiro unsigned char *volatile pbp; 30740266059SGregory Neil Shapiro unsigned char peekbuf[8]; 308c2aa98e2SPeter Wemm char bufbuf[MAXLINE]; 309c2aa98e2SPeter Wemm 31040266059SGregory Neil Shapiro df = NULL; 31140266059SGregory Neil Shapiro ignrdot = smtpmode ? false : IgnrDot; 31240266059SGregory Neil Shapiro dbto = smtpmode ? TimeOuts.to_datablock : 0; 31340266059SGregory Neil Shapiro c = SM_IO_EOF; 31440266059SGregory Neil Shapiro inputerr = false; 315c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 31640266059SGregory Neil Shapiro hdrslen = 0; 31740266059SGregory Neil Shapiro numhdrs = 0; 31840266059SGregory Neil Shapiro HasEightBits = false; 31940266059SGregory Neil Shapiro buf = bp = bufbuf; 32040266059SGregory Neil Shapiro buflen = sizeof bufbuf; 32140266059SGregory Neil Shapiro pbp = peekbuf; 32240266059SGregory Neil Shapiro istate = IS_BOL; 32340266059SGregory Neil Shapiro mstate = SaveFrom ? MS_HEADER : MS_UFROM; 32440266059SGregory Neil Shapiro CollectProgress = false; 325c2aa98e2SPeter Wemm 326c2aa98e2SPeter Wemm /* 327c2aa98e2SPeter Wemm ** Tell ARPANET to go ahead. 328c2aa98e2SPeter Wemm */ 329c2aa98e2SPeter Wemm 330c2aa98e2SPeter Wemm if (smtpmode) 331c2aa98e2SPeter Wemm message("354 Enter mail, end with \".\" on a line by itself"); 332c2aa98e2SPeter Wemm 333c2aa98e2SPeter Wemm if (tTd(30, 2)) 33440266059SGregory Neil Shapiro sm_dprintf("collect\n"); 335c2aa98e2SPeter Wemm 336c2aa98e2SPeter Wemm /* 337c2aa98e2SPeter Wemm ** Read the message. 338c2aa98e2SPeter Wemm ** 339c2aa98e2SPeter Wemm ** This is done using two interleaved state machines. 340c2aa98e2SPeter Wemm ** The input state machine is looking for things like 341c2aa98e2SPeter Wemm ** hidden dots; the message state machine is handling 342c2aa98e2SPeter Wemm ** the larger picture (e.g., header versus body). 343c2aa98e2SPeter Wemm */ 344c2aa98e2SPeter Wemm 345c2aa98e2SPeter Wemm if (dbto != 0) 346c2aa98e2SPeter Wemm { 347c2aa98e2SPeter Wemm /* handle possible input timeout */ 348c2aa98e2SPeter Wemm if (setjmp(CtxCollectTimeout) != 0) 349c2aa98e2SPeter Wemm { 350c2aa98e2SPeter Wemm if (LogLevel > 2) 351c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 352c2aa98e2SPeter Wemm "timeout waiting for input from %s during message collect", 35340266059SGregory Neil Shapiro CURHOSTNAME); 354c2aa98e2SPeter Wemm errno = 0; 35513bd1963SGregory Neil Shapiro if (smtpmode) 35613bd1963SGregory Neil Shapiro { 35713bd1963SGregory Neil Shapiro /* 35813bd1963SGregory Neil Shapiro ** Override e_message in usrerr() as this 35913bd1963SGregory Neil Shapiro ** is the reason for failure that should 36013bd1963SGregory Neil Shapiro ** be logged for undelivered recipients. 36113bd1963SGregory Neil Shapiro */ 36213bd1963SGregory Neil Shapiro 36313bd1963SGregory Neil Shapiro e->e_message = NULL; 36413bd1963SGregory Neil Shapiro } 36506f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 timeout waiting for input during message collect"); 366c2aa98e2SPeter Wemm goto readerr; 367c2aa98e2SPeter Wemm } 36840266059SGregory Neil Shapiro CollectTimeout = sm_setevent(dbto, collecttimeout, dbto); 369c2aa98e2SPeter Wemm } 370c2aa98e2SPeter Wemm 371a7ec597cSGregory Neil Shapiro if (rsetsize) 37240266059SGregory Neil Shapiro e->e_msgsize = 0; 373c2aa98e2SPeter Wemm for (;;) 374c2aa98e2SPeter Wemm { 375c2aa98e2SPeter Wemm if (tTd(30, 35)) 37640266059SGregory Neil Shapiro sm_dprintf("top, istate=%d, mstate=%d\n", istate, 37740266059SGregory Neil Shapiro mstate); 378c2aa98e2SPeter Wemm for (;;) 379c2aa98e2SPeter Wemm { 380c2aa98e2SPeter Wemm if (pbp > peekbuf) 381c2aa98e2SPeter Wemm c = *--pbp; 382c2aa98e2SPeter Wemm else 383c2aa98e2SPeter Wemm { 38440266059SGregory Neil Shapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 385c2aa98e2SPeter Wemm { 386c2aa98e2SPeter Wemm errno = 0; 38740266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 38840266059SGregory Neil Shapiro if (c == SM_IO_EOF && errno == EINTR) 38942e5d165SGregory Neil Shapiro { 39042e5d165SGregory Neil Shapiro /* Interrupted, retry */ 39140266059SGregory Neil Shapiro sm_io_clearerr(fp); 39242e5d165SGregory Neil Shapiro continue; 39342e5d165SGregory Neil Shapiro } 39442e5d165SGregory Neil Shapiro break; 395c2aa98e2SPeter Wemm } 39640266059SGregory Neil Shapiro CollectProgress = true; 397c2aa98e2SPeter Wemm if (TrafficLogFile != NULL && !headeronly) 398c2aa98e2SPeter Wemm { 399c2aa98e2SPeter Wemm if (istate == IS_BOL) 40040266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 40140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 4028774250cSGregory Neil Shapiro "%05d <<< ", 40340266059SGregory Neil Shapiro (int) CurrentPid); 40440266059SGregory Neil Shapiro if (c == SM_IO_EOF) 40540266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 40640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 4078774250cSGregory Neil Shapiro "[EOF]\n"); 408c2aa98e2SPeter Wemm else 40940266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 41040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 41140266059SGregory Neil Shapiro c); 412c2aa98e2SPeter Wemm } 41340266059SGregory Neil Shapiro if (c == SM_IO_EOF) 414c2aa98e2SPeter Wemm goto readerr; 415c2aa98e2SPeter Wemm if (SevenBitInput) 416c2aa98e2SPeter Wemm c &= 0x7f; 417c2aa98e2SPeter Wemm else 418c2aa98e2SPeter Wemm HasEightBits |= bitset(0x80, c); 419c2aa98e2SPeter Wemm } 420c2aa98e2SPeter Wemm if (tTd(30, 94)) 42140266059SGregory Neil Shapiro sm_dprintf("istate=%d, c=%c (0x%x)\n", 42206f25ae9SGregory Neil Shapiro istate, (char) c, c); 423c2aa98e2SPeter Wemm switch (istate) 424c2aa98e2SPeter Wemm { 425c2aa98e2SPeter Wemm case IS_BOL: 426c2aa98e2SPeter Wemm if (c == '.') 427c2aa98e2SPeter Wemm { 428c2aa98e2SPeter Wemm istate = IS_DOT; 429c2aa98e2SPeter Wemm continue; 430c2aa98e2SPeter Wemm } 431c2aa98e2SPeter Wemm break; 432c2aa98e2SPeter Wemm 433c2aa98e2SPeter Wemm case IS_DOT: 434c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot && 435c2aa98e2SPeter Wemm !bitset(EF_NL_NOT_EOL, e->e_flags)) 436c2aa98e2SPeter Wemm goto readerr; 437c2aa98e2SPeter Wemm else if (c == '\r' && 438c2aa98e2SPeter Wemm !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 439c2aa98e2SPeter Wemm { 440c2aa98e2SPeter Wemm istate = IS_DOTCR; 441c2aa98e2SPeter Wemm continue; 442c2aa98e2SPeter Wemm } 443605302a5SGregory Neil Shapiro else if (ignrdot || 444605302a5SGregory Neil Shapiro (c != '.' && 445605302a5SGregory Neil Shapiro OpMode != MD_SMTP && 446c2aa98e2SPeter Wemm OpMode != MD_DAEMON && 447c2aa98e2SPeter Wemm OpMode != MD_ARPAFTP)) 448605302a5SGregory Neil Shapiro 449c2aa98e2SPeter Wemm { 4505ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 451c2aa98e2SPeter Wemm *pbp++ = c; 452c2aa98e2SPeter Wemm c = '.'; 453c2aa98e2SPeter Wemm } 454c2aa98e2SPeter Wemm break; 455c2aa98e2SPeter Wemm 456c2aa98e2SPeter Wemm case IS_DOTCR: 457c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot) 458c2aa98e2SPeter Wemm goto readerr; 459c2aa98e2SPeter Wemm else 460c2aa98e2SPeter Wemm { 461c2aa98e2SPeter Wemm /* push back the ".\rx" */ 4625ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 463c2aa98e2SPeter Wemm *pbp++ = c; 464605302a5SGregory Neil Shapiro if (OpMode != MD_SMTP && 465605302a5SGregory Neil Shapiro OpMode != MD_DAEMON && 466605302a5SGregory Neil Shapiro OpMode != MD_ARPAFTP) 467605302a5SGregory Neil Shapiro { 4685ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 4695ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 470c2aa98e2SPeter Wemm *pbp++ = '\r'; 471c2aa98e2SPeter Wemm c = '.'; 472c2aa98e2SPeter Wemm } 473605302a5SGregory Neil Shapiro else 474605302a5SGregory Neil Shapiro c = '\r'; 475605302a5SGregory Neil Shapiro } 476c2aa98e2SPeter Wemm break; 477c2aa98e2SPeter Wemm 478c2aa98e2SPeter Wemm case IS_CR: 479c2aa98e2SPeter Wemm if (c == '\n') 480c2aa98e2SPeter Wemm istate = IS_BOL; 481c2aa98e2SPeter Wemm else 482c2aa98e2SPeter Wemm { 48340266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 48440266059SGregory Neil Shapiro c); 485c2aa98e2SPeter Wemm c = '\r'; 486c2aa98e2SPeter Wemm istate = IS_NORM; 487c2aa98e2SPeter Wemm } 488c2aa98e2SPeter Wemm goto bufferchar; 489c2aa98e2SPeter Wemm } 490c2aa98e2SPeter Wemm 491c2aa98e2SPeter Wemm if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 492c2aa98e2SPeter Wemm { 493c2aa98e2SPeter Wemm istate = IS_CR; 494c2aa98e2SPeter Wemm continue; 495c2aa98e2SPeter Wemm } 49640266059SGregory Neil Shapiro else if (c == '\n' && !bitset(EF_NL_NOT_EOL, 49740266059SGregory Neil Shapiro e->e_flags)) 498c2aa98e2SPeter Wemm istate = IS_BOL; 499c2aa98e2SPeter Wemm else 500c2aa98e2SPeter Wemm istate = IS_NORM; 501c2aa98e2SPeter Wemm 502c2aa98e2SPeter Wemm bufferchar: 503c2aa98e2SPeter Wemm if (!headeronly) 50442e5d165SGregory Neil Shapiro { 50542e5d165SGregory Neil Shapiro /* no overflow? */ 50642e5d165SGregory Neil Shapiro if (e->e_msgsize >= 0) 50742e5d165SGregory Neil Shapiro { 508c2aa98e2SPeter Wemm e->e_msgsize++; 50942e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 && 51042e5d165SGregory Neil Shapiro !bitset(EF_TOOBIG, e->e_flags) && 51142e5d165SGregory Neil Shapiro e->e_msgsize > MaxMessageSize) 51242e5d165SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 51342e5d165SGregory Neil Shapiro } 51442e5d165SGregory Neil Shapiro } 51525bab6e9SPeter Wemm switch (mstate) 516c2aa98e2SPeter Wemm { 51725bab6e9SPeter Wemm case MS_BODY: 518c2aa98e2SPeter Wemm /* just put the character out */ 51942e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 52040266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 52140266059SGregory Neil Shapiro c); 52240266059SGregory Neil Shapiro 52306f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 52425bab6e9SPeter Wemm 52525bab6e9SPeter Wemm case MS_DISCARD: 526c2aa98e2SPeter Wemm continue; 527c2aa98e2SPeter Wemm } 528c2aa98e2SPeter Wemm 529c2aa98e2SPeter Wemm /* header -- buffer up */ 530c2aa98e2SPeter Wemm if (bp >= &buf[buflen - 2]) 531c2aa98e2SPeter Wemm { 532c2aa98e2SPeter Wemm char *obuf; 533c2aa98e2SPeter Wemm 534c2aa98e2SPeter Wemm if (mstate != MS_HEADER) 535c2aa98e2SPeter Wemm break; 536c2aa98e2SPeter Wemm 537c2aa98e2SPeter Wemm /* out of space for header */ 538c2aa98e2SPeter Wemm obuf = buf; 539c2aa98e2SPeter Wemm if (buflen < MEMCHUNKSIZE) 540c2aa98e2SPeter Wemm buflen *= 2; 541c2aa98e2SPeter Wemm else 542c2aa98e2SPeter Wemm buflen += MEMCHUNKSIZE; 543c2aa98e2SPeter Wemm buf = xalloc(buflen); 54406f25ae9SGregory Neil Shapiro memmove(buf, obuf, bp - obuf); 545c2aa98e2SPeter Wemm bp = &buf[bp - obuf]; 546c2aa98e2SPeter Wemm if (obuf != bufbuf) 54740266059SGregory Neil Shapiro sm_free(obuf); /* XXX */ 548c2aa98e2SPeter Wemm } 54940266059SGregory Neil Shapiro 55040266059SGregory Neil Shapiro /* 55140266059SGregory Neil Shapiro ** XXX Notice: the logic here is broken. 55240266059SGregory Neil Shapiro ** An input to sendmail that doesn't contain a 55340266059SGregory Neil Shapiro ** header but starts immediately with the body whose 55440266059SGregory Neil Shapiro ** first line contain characters which match the 55540266059SGregory Neil Shapiro ** following "if" will cause problems: those 55640266059SGregory Neil Shapiro ** characters will NOT appear in the output... 55740266059SGregory Neil Shapiro ** Do we care? 55840266059SGregory Neil Shapiro */ 55940266059SGregory Neil Shapiro 560c2aa98e2SPeter Wemm if (c >= 0200 && c <= 0237) 561c2aa98e2SPeter Wemm { 56240266059SGregory Neil Shapiro #if 0 /* causes complaints -- figure out something for 8.n+1 */ 563c2aa98e2SPeter Wemm usrerr("Illegal character 0x%x in header", c); 56406f25ae9SGregory Neil Shapiro #else /* 0 */ 56506f25ae9SGregory Neil Shapiro /* EMPTY */ 56606f25ae9SGregory Neil Shapiro #endif /* 0 */ 567c2aa98e2SPeter Wemm } 568c2aa98e2SPeter Wemm else if (c != '\0') 56925bab6e9SPeter Wemm { 570c2aa98e2SPeter Wemm *bp++ = c; 57140266059SGregory Neil Shapiro ++hdrslen; 57213058a91SGregory Neil Shapiro if (!headeronly && 57313058a91SGregory Neil Shapiro MaxHeadersLength > 0 && 574602a2b1bSGregory Neil Shapiro hdrslen > MaxHeadersLength) 57525bab6e9SPeter Wemm { 57625bab6e9SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 5772e43090eSPeter Wemm "headers too large (%d max) from %s during message collect", 5782e43090eSPeter Wemm MaxHeadersLength, 57940266059SGregory Neil Shapiro CURHOSTNAME); 58025bab6e9SPeter Wemm errno = 0; 58125bab6e9SPeter Wemm e->e_flags |= EF_CLRQUEUE; 58225bab6e9SPeter Wemm e->e_status = "5.6.0"; 58306f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 58406f25ae9SGregory Neil Shapiro "552 Headers too large (%d max)", 5852e43090eSPeter Wemm MaxHeadersLength); 58625bab6e9SPeter Wemm mstate = MS_DISCARD; 58725bab6e9SPeter Wemm } 58825bab6e9SPeter Wemm } 589c2aa98e2SPeter Wemm if (istate == IS_BOL) 590c2aa98e2SPeter Wemm break; 591c2aa98e2SPeter Wemm } 592c2aa98e2SPeter Wemm *bp = '\0'; 593c2aa98e2SPeter Wemm 594c2aa98e2SPeter Wemm nextstate: 595c2aa98e2SPeter Wemm if (tTd(30, 35)) 59640266059SGregory Neil Shapiro sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 597c2aa98e2SPeter Wemm istate, mstate, buf); 598c2aa98e2SPeter Wemm switch (mstate) 599c2aa98e2SPeter Wemm { 600c2aa98e2SPeter Wemm case MS_UFROM: 601c2aa98e2SPeter Wemm mstate = MS_HEADER; 602c2aa98e2SPeter Wemm #ifndef NOTUNIX 603c2aa98e2SPeter Wemm if (strncmp(buf, "From ", 5) == 0) 604c2aa98e2SPeter Wemm { 605c2aa98e2SPeter Wemm bp = buf; 606c2aa98e2SPeter Wemm eatfrom(buf, e); 607c2aa98e2SPeter Wemm continue; 608c2aa98e2SPeter Wemm } 60906f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 61006f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm case MS_HEADER: 613c2aa98e2SPeter Wemm if (!isheader(buf)) 614c2aa98e2SPeter Wemm { 615c2aa98e2SPeter Wemm mstate = MS_BODY; 616c2aa98e2SPeter Wemm goto nextstate; 617c2aa98e2SPeter Wemm } 618c2aa98e2SPeter Wemm 619c2aa98e2SPeter Wemm /* check for possible continuation line */ 620c2aa98e2SPeter Wemm do 621c2aa98e2SPeter Wemm { 62240266059SGregory Neil Shapiro sm_io_clearerr(fp); 623c2aa98e2SPeter Wemm errno = 0; 62440266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 62540266059SGregory Neil Shapiro } while (c == SM_IO_EOF && errno == EINTR); 62640266059SGregory Neil Shapiro if (c != SM_IO_EOF) 62740266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 628c2aa98e2SPeter Wemm if (c == ' ' || c == '\t') 629c2aa98e2SPeter Wemm { 630c2aa98e2SPeter Wemm /* yep -- defer this */ 631c2aa98e2SPeter Wemm continue; 632c2aa98e2SPeter Wemm } 633c2aa98e2SPeter Wemm 634c2aa98e2SPeter Wemm /* trim off trailing CRLF or NL */ 6355ef517c0SGregory Neil Shapiro SM_ASSERT(bp > buf); 636c2aa98e2SPeter Wemm if (*--bp != '\n' || *--bp != '\r') 637c2aa98e2SPeter Wemm bp++; 638c2aa98e2SPeter Wemm *bp = '\0'; 63925bab6e9SPeter Wemm 64006f25ae9SGregory Neil Shapiro if (bitset(H_EOH, chompheader(buf, 64106f25ae9SGregory Neil Shapiro CHHDR_CHECK | CHHDR_USER, 64206f25ae9SGregory Neil Shapiro hdrp, e))) 643c2aa98e2SPeter Wemm { 644c2aa98e2SPeter Wemm mstate = MS_BODY; 645c2aa98e2SPeter Wemm goto nextstate; 646c2aa98e2SPeter Wemm } 64706f25ae9SGregory Neil Shapiro numhdrs++; 648c2aa98e2SPeter Wemm break; 649c2aa98e2SPeter Wemm 650c2aa98e2SPeter Wemm case MS_BODY: 651c2aa98e2SPeter Wemm if (tTd(30, 1)) 65240266059SGregory Neil Shapiro sm_dprintf("EOH\n"); 65306f25ae9SGregory Neil Shapiro 654c2aa98e2SPeter Wemm if (headeronly) 655c2aa98e2SPeter Wemm goto readerr; 65606f25ae9SGregory Neil Shapiro 65740266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 65840266059SGregory Neil Shapiro if (df == NULL) 65940266059SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 66006f25ae9SGregory Neil Shapiro 661c2aa98e2SPeter Wemm bp = buf; 662c2aa98e2SPeter Wemm 663c2aa98e2SPeter Wemm /* toss blank line */ 664c2aa98e2SPeter Wemm if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 665c2aa98e2SPeter Wemm bp[0] == '\r' && bp[1] == '\n') || 666c2aa98e2SPeter Wemm (!bitset(EF_NL_NOT_EOL, e->e_flags) && 667c2aa98e2SPeter Wemm bp[0] == '\n')) 668c2aa98e2SPeter Wemm { 669c2aa98e2SPeter Wemm break; 670c2aa98e2SPeter Wemm } 671c2aa98e2SPeter Wemm 672c2aa98e2SPeter Wemm /* if not a blank separator, write it out */ 67342e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 674c2aa98e2SPeter Wemm { 675c2aa98e2SPeter Wemm while (*bp != '\0') 67640266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 67740266059SGregory Neil Shapiro *bp++); 678c2aa98e2SPeter Wemm } 679c2aa98e2SPeter Wemm break; 680c2aa98e2SPeter Wemm } 681c2aa98e2SPeter Wemm bp = buf; 682c2aa98e2SPeter Wemm } 683c2aa98e2SPeter Wemm 684c2aa98e2SPeter Wemm readerr: 68540266059SGregory Neil Shapiro if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 686c2aa98e2SPeter Wemm { 68740266059SGregory Neil Shapiro const char *errmsg; 688c2aa98e2SPeter Wemm 68940266059SGregory Neil Shapiro if (sm_io_eof(fp)) 69040266059SGregory Neil Shapiro errmsg = "unexpected close"; 69140266059SGregory Neil Shapiro else 69240266059SGregory Neil Shapiro errmsg = sm_errstring(errno); 693c2aa98e2SPeter Wemm if (tTd(30, 1)) 69440266059SGregory Neil Shapiro sm_dprintf("collect: premature EOM: %s\n", errmsg); 69540266059SGregory Neil Shapiro if (LogLevel > 1) 696c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 697c2aa98e2SPeter Wemm "collect: premature EOM: %s", errmsg); 69840266059SGregory Neil Shapiro inputerr = true; 699c2aa98e2SPeter Wemm } 700c2aa98e2SPeter Wemm 701c2aa98e2SPeter Wemm /* reset global timer */ 7028774250cSGregory Neil Shapiro if (CollectTimeout != NULL) 70340266059SGregory Neil Shapiro sm_clrevent(CollectTimeout); 704c2aa98e2SPeter Wemm 705c2aa98e2SPeter Wemm if (headeronly) 706c2aa98e2SPeter Wemm return; 707c2aa98e2SPeter Wemm 70840266059SGregory Neil Shapiro if (mstate != MS_BODY) 70940266059SGregory Neil Shapiro { 71040266059SGregory Neil Shapiro /* no body or discard, so we never opened the data file */ 71140266059SGregory Neil Shapiro SM_ASSERT(df == NULL); 71240266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 71340266059SGregory Neil Shapiro } 71440266059SGregory Neil Shapiro 71506f25ae9SGregory Neil Shapiro if (df == NULL) 716c2aa98e2SPeter Wemm { 71706f25ae9SGregory Neil Shapiro /* skip next few clauses */ 71806f25ae9SGregory Neil Shapiro /* EMPTY */ 71906f25ae9SGregory Neil Shapiro } 72040266059SGregory Neil Shapiro else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 72106f25ae9SGregory Neil Shapiro { 72240266059SGregory Neil Shapiro dferror(df, "sm_io_flush||sm_io_error", e); 72340266059SGregory Neil Shapiro flush_errors(true); 72440266059SGregory Neil Shapiro finis(true, true, ExitStat); 72506f25ae9SGregory Neil Shapiro /* NOTREACHED */ 72606f25ae9SGregory Neil Shapiro } 72740266059SGregory Neil Shapiro else if (SuperSafe != SAFE_REALLY) 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 } 75740266059SGregory Neil Shapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 && 75840266059SGregory Neil Shapiro fsync(afd) < 0) 759602a2b1bSGregory Neil Shapiro { 76040266059SGregory Neil Shapiro dferror(df, "fsync", e); 76140266059SGregory Neil Shapiro flush_errors(true); 76240266059SGregory Neil Shapiro finis(true, true, ExitStat); 763602a2b1bSGregory Neil Shapiro /* NOTREACHED */ 764602a2b1bSGregory Neil Shapiro } 76540266059SGregory Neil Shapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 76606f25ae9SGregory Neil Shapiro { 76740266059SGregory Neil Shapiro dferror(df, "sm_io_close", e); 76840266059SGregory Neil Shapiro flush_errors(true); 76940266059SGregory Neil Shapiro finis(true, true, ExitStat); 77006f25ae9SGregory Neil Shapiro /* NOTREACHED */ 77106f25ae9SGregory Neil Shapiro } 77206f25ae9SGregory Neil Shapiro else 77306f25ae9SGregory Neil Shapiro { 77406f25ae9SGregory Neil Shapiro /* everything is happily flushed to disk */ 77506f25ae9SGregory Neil Shapiro df = NULL; 77640266059SGregory Neil Shapiro 77740266059SGregory Neil Shapiro /* remove from available space in filesystem */ 77840266059SGregory Neil Shapiro updfs(e, false, true); 779c2aa98e2SPeter Wemm } 780c2aa98e2SPeter Wemm 781c2aa98e2SPeter Wemm /* An EOF when running SMTP is an error */ 782c2aa98e2SPeter Wemm if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 783c2aa98e2SPeter Wemm { 784c2aa98e2SPeter Wemm char *host; 785c2aa98e2SPeter Wemm char *problem; 786959366dcSGregory Neil Shapiro ADDRESS *q; 787c2aa98e2SPeter Wemm 788c2aa98e2SPeter Wemm host = RealHostName; 789c2aa98e2SPeter Wemm if (host == NULL) 790c2aa98e2SPeter Wemm host = "localhost"; 791c2aa98e2SPeter Wemm 79240266059SGregory Neil Shapiro if (sm_io_eof(fp)) 793c2aa98e2SPeter Wemm problem = "unexpected close"; 79440266059SGregory Neil Shapiro else if (sm_io_error(fp)) 795c2aa98e2SPeter Wemm problem = "I/O error"; 796c2aa98e2SPeter Wemm else 797c2aa98e2SPeter Wemm problem = "read timeout"; 79840266059SGregory Neil Shapiro if (LogLevel > 0 && sm_io_eof(fp)) 799c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 80040266059SGregory Neil Shapiro "collect: %s on connection from %.100s, sender=%s", 801c2aa98e2SPeter Wemm problem, host, 80240266059SGregory Neil Shapiro shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 80340266059SGregory Neil Shapiro if (sm_io_eof(fp)) 80406f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 805c2aa98e2SPeter Wemm problem, host, 806c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 807c2aa98e2SPeter Wemm else 80806f25ae9SGregory Neil Shapiro syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 809c2aa98e2SPeter Wemm problem, host, 810c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 811c2aa98e2SPeter Wemm 812c2aa98e2SPeter Wemm /* don't return an error indication */ 813c2aa98e2SPeter Wemm e->e_to = NULL; 814c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 815c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 816c2aa98e2SPeter Wemm 817959366dcSGregory Neil Shapiro /* Don't send any message notification to sender */ 818959366dcSGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 819959366dcSGregory Neil Shapiro { 820959366dcSGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 821959366dcSGregory Neil Shapiro continue; 822959366dcSGregory Neil Shapiro q->q_state = QS_FATALERR; 823959366dcSGregory Neil Shapiro } 824959366dcSGregory Neil Shapiro 82540266059SGregory Neil Shapiro finis(true, true, ExitStat); 82606f25ae9SGregory Neil Shapiro /* NOTREACHED */ 827c2aa98e2SPeter Wemm } 828c2aa98e2SPeter Wemm 82940266059SGregory Neil Shapiro /* Log collection information. */ 83040266059SGregory Neil Shapiro if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 831c2aa98e2SPeter Wemm { 83240266059SGregory Neil Shapiro logsender(e, e->e_msgid); 83340266059SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER; 834c2aa98e2SPeter Wemm } 835c2aa98e2SPeter Wemm 836c2aa98e2SPeter Wemm /* check for message too large */ 83742e5d165SGregory Neil Shapiro if (bitset(EF_TOOBIG, e->e_flags)) 838c2aa98e2SPeter Wemm { 839c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 84040266059SGregory Neil Shapiro if (!bitset(EF_FATALERRS, e->e_flags)) 84140266059SGregory Neil Shapiro { 842c2aa98e2SPeter Wemm e->e_status = "5.2.3"; 84306f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 84406f25ae9SGregory Neil Shapiro "552 Message exceeds maximum fixed size (%ld)", 845c2aa98e2SPeter Wemm MaxMessageSize); 846c2aa98e2SPeter Wemm if (LogLevel > 6) 847c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 848c2aa98e2SPeter Wemm "message size (%ld) exceeds maximum (%ld)", 849c2aa98e2SPeter Wemm e->e_msgsize, MaxMessageSize); 850c2aa98e2SPeter Wemm } 85140266059SGregory Neil Shapiro } 852c2aa98e2SPeter Wemm 853c2aa98e2SPeter Wemm /* check for illegal 8-bit data */ 854c2aa98e2SPeter Wemm if (HasEightBits) 855c2aa98e2SPeter Wemm { 856c2aa98e2SPeter Wemm e->e_flags |= EF_HAS8BIT; 857c2aa98e2SPeter Wemm if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 858c2aa98e2SPeter Wemm !bitset(EF_IS_MIME, e->e_flags)) 859c2aa98e2SPeter Wemm { 860c2aa98e2SPeter Wemm e->e_status = "5.6.1"; 86106f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 862c2aa98e2SPeter Wemm } 863c2aa98e2SPeter Wemm } 864c2aa98e2SPeter Wemm else 865c2aa98e2SPeter Wemm { 866c2aa98e2SPeter Wemm /* if it claimed to be 8 bits, well, it lied.... */ 867c2aa98e2SPeter Wemm if (e->e_bodytype != NULL && 86840266059SGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 869c2aa98e2SPeter Wemm e->e_bodytype = "7BIT"; 870c2aa98e2SPeter Wemm } 871c2aa98e2SPeter Wemm 87240266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 87306f25ae9SGregory Neil Shapiro { 87440266059SGregory Neil Shapiro char *dfname = queuename(e, DATAFL_LETTER); 87540266059SGregory Neil Shapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 87640266059SGregory Neil Shapiro SM_IO_RDONLY, NULL)) == NULL) 877c2aa98e2SPeter Wemm { 878c2aa98e2SPeter Wemm /* we haven't acked receipt yet, so just chuck this */ 87940266059SGregory Neil Shapiro syserr("@Cannot reopen %s", dfname); 88040266059SGregory Neil Shapiro finis(true, true, ExitStat); 88106f25ae9SGregory Neil Shapiro /* NOTREACHED */ 882c2aa98e2SPeter Wemm } 883c2aa98e2SPeter Wemm } 88406f25ae9SGregory Neil Shapiro else 88506f25ae9SGregory Neil Shapiro e->e_dfp = df; 886605302a5SGregory Neil Shapiro 887605302a5SGregory Neil Shapiro /* collect statistics */ 888605302a5SGregory Neil Shapiro if (OpMode != MD_VERIFY) 889a7ec597cSGregory Neil Shapiro { 890a7ec597cSGregory Neil Shapiro /* 891a7ec597cSGregory Neil Shapiro ** Recalculate e_msgpriority, it is done at in eatheader() 892a7ec597cSGregory Neil Shapiro ** which is called (in 8.12) after the header is collected, 893a7ec597cSGregory Neil Shapiro ** hence e_msgsize is (most likely) incorrect. 894a7ec597cSGregory Neil Shapiro */ 895a7ec597cSGregory Neil Shapiro 896a7ec597cSGregory Neil Shapiro e->e_msgpriority = e->e_msgsize 897a7ec597cSGregory Neil Shapiro - e->e_class * WkClassFact 898a7ec597cSGregory Neil Shapiro + e->e_nrcpts * WkRecipFact; 899a7ec597cSGregory Neil Shapiro if (tTd(90, 1)) 900a7ec597cSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 901a7ec597cSGregory Neil Shapiro "collect: at end: msgsize=%ld, msgpriority=%ld", 902a7ec597cSGregory Neil Shapiro e->e_msgsize, e->e_msgpriority); 903605302a5SGregory Neil Shapiro markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 90406f25ae9SGregory Neil Shapiro } 905a7ec597cSGregory Neil Shapiro } 906c2aa98e2SPeter Wemm 907c2aa98e2SPeter Wemm static void 908c2aa98e2SPeter Wemm collecttimeout(timeout) 909c2aa98e2SPeter Wemm time_t timeout; 910c2aa98e2SPeter Wemm { 9118774250cSGregory Neil Shapiro int save_errno = errno; 912c2aa98e2SPeter Wemm 9138774250cSGregory Neil Shapiro /* 9148774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 9158774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 9168774250cSGregory Neil Shapiro ** DOING. 9178774250cSGregory Neil Shapiro */ 9188774250cSGregory Neil Shapiro 9198774250cSGregory Neil Shapiro if (CollectProgress) 9208774250cSGregory Neil Shapiro { 9218774250cSGregory Neil Shapiro /* reset the timeout */ 92240266059SGregory Neil Shapiro CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout, 9238774250cSGregory Neil Shapiro timeout); 92440266059SGregory Neil Shapiro CollectProgress = false; 925c2aa98e2SPeter Wemm } 9268774250cSGregory Neil Shapiro else 9278774250cSGregory Neil Shapiro { 9288774250cSGregory Neil Shapiro /* event is done */ 9298774250cSGregory Neil Shapiro CollectTimeout = NULL; 9308774250cSGregory Neil Shapiro } 9318774250cSGregory Neil Shapiro 9328774250cSGregory Neil Shapiro /* if no progress was made or problem resetting event, die now */ 9338774250cSGregory Neil Shapiro if (CollectTimeout == NULL) 9348774250cSGregory Neil Shapiro { 9358774250cSGregory Neil Shapiro errno = ETIMEDOUT; 9368774250cSGregory Neil Shapiro longjmp(CtxCollectTimeout, 1); 9378774250cSGregory Neil Shapiro } 9388774250cSGregory Neil Shapiro errno = save_errno; 9398774250cSGregory Neil Shapiro } 94040266059SGregory Neil Shapiro /* 94106f25ae9SGregory Neil Shapiro ** DFERROR -- signal error on writing the data file. 942c2aa98e2SPeter Wemm ** 94340266059SGregory Neil Shapiro ** Called by collect(). Collect() always terminates the process 94440266059SGregory Neil Shapiro ** immediately after calling dferror(), which means that the SMTP 94540266059SGregory Neil Shapiro ** session will be terminated, which means that any error message 94640266059SGregory Neil Shapiro ** issued by dferror must be a 421 error, as per RFC 821. 94740266059SGregory Neil Shapiro ** 948c2aa98e2SPeter Wemm ** Parameters: 94906f25ae9SGregory Neil Shapiro ** df -- the file pointer for the data file. 95006f25ae9SGregory Neil Shapiro ** msg -- detailed message. 951c2aa98e2SPeter Wemm ** e -- the current envelope. 952c2aa98e2SPeter Wemm ** 953c2aa98e2SPeter Wemm ** Returns: 954c2aa98e2SPeter Wemm ** none. 955c2aa98e2SPeter Wemm ** 956c2aa98e2SPeter Wemm ** Side Effects: 957c2aa98e2SPeter Wemm ** Gives an error message. 958c2aa98e2SPeter Wemm ** Arranges for following output to go elsewhere. 959c2aa98e2SPeter Wemm */ 960c2aa98e2SPeter Wemm 96106f25ae9SGregory Neil Shapiro static void 96206f25ae9SGregory Neil Shapiro dferror(df, msg, e) 96340266059SGregory Neil Shapiro SM_FILE_T *volatile df; 96406f25ae9SGregory Neil Shapiro char *msg; 965c2aa98e2SPeter Wemm register ENVELOPE *e; 966c2aa98e2SPeter Wemm { 96706f25ae9SGregory Neil Shapiro char *dfname; 96806f25ae9SGregory Neil Shapiro 96940266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 970c2aa98e2SPeter Wemm setstat(EX_IOERR); 971c2aa98e2SPeter Wemm if (errno == ENOSPC) 972c2aa98e2SPeter Wemm { 973c2aa98e2SPeter Wemm #if STAT64 > 0 974c2aa98e2SPeter Wemm struct stat64 st; 97506f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 976c2aa98e2SPeter Wemm struct stat st; 97706f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 978c2aa98e2SPeter Wemm long avail; 979c2aa98e2SPeter Wemm long bsize; 980c2aa98e2SPeter Wemm 981c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 982c2aa98e2SPeter Wemm 983c2aa98e2SPeter Wemm if ( 984c2aa98e2SPeter Wemm #if STAT64 > 0 98540266059SGregory Neil Shapiro fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 98606f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 98740266059SGregory Neil Shapiro fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 98806f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 989c2aa98e2SPeter Wemm < 0) 990c2aa98e2SPeter Wemm st.st_size = 0; 99140266059SGregory Neil Shapiro (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 99240266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df); 993c2aa98e2SPeter Wemm if (st.st_size <= 0) 99440266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 99540266059SGregory Neil Shapiro "\n*** Mail could not be accepted"); 996c2aa98e2SPeter Wemm else 99740266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 99840266059SGregory Neil Shapiro "\n*** Mail of at least %llu bytes could not be accepted\n", 99940266059SGregory Neil Shapiro (ULONGLONG_T) st.st_size); 100040266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 100140266059SGregory Neil Shapiro "*** at %s due to lack of disk space for temp file.\n", 1002c2aa98e2SPeter Wemm MyHostName); 100340266059SGregory Neil Shapiro avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 100440266059SGregory Neil Shapiro &bsize); 1005c2aa98e2SPeter Wemm if (avail > 0) 1006c2aa98e2SPeter Wemm { 1007c2aa98e2SPeter Wemm if (bsize > 1024) 1008c2aa98e2SPeter Wemm avail *= bsize / 1024; 1009c2aa98e2SPeter Wemm else if (bsize < 1024) 1010c2aa98e2SPeter Wemm avail /= 1024 / bsize; 101140266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 101240266059SGregory Neil Shapiro "*** Currently, %ld kilobytes are available for mail temp files.\n", 1013c2aa98e2SPeter Wemm avail); 1014c2aa98e2SPeter Wemm } 101540266059SGregory Neil Shapiro #if 0 101640266059SGregory Neil Shapiro /* Wrong response code; should be 421. */ 1017c2aa98e2SPeter Wemm e->e_status = "4.3.1"; 101806f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 101940266059SGregory Neil Shapiro #else /* 0 */ 102040266059SGregory Neil Shapiro syserr("421 4.3.1 Out of disk space for temp file"); 102140266059SGregory Neil Shapiro #endif /* 0 */ 1022c2aa98e2SPeter Wemm } 1023c2aa98e2SPeter Wemm else 102440266059SGregory Neil Shapiro syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", 102594c01205SGregory Neil Shapiro dfname, msg, (int) geteuid(), (int) getegid()); 102640266059SGregory Neil Shapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 102740266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df) == NULL) 1028c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 102940266059SGregory Neil Shapiro "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 103040266059SGregory Neil Shapiro sm_errstring(errno)); 1031c2aa98e2SPeter Wemm } 103240266059SGregory Neil Shapiro /* 1033c2aa98e2SPeter Wemm ** EATFROM -- chew up a UNIX style from line and process 1034c2aa98e2SPeter Wemm ** 1035c2aa98e2SPeter Wemm ** This does indeed make some assumptions about the format 1036c2aa98e2SPeter Wemm ** of UNIX messages. 1037c2aa98e2SPeter Wemm ** 1038c2aa98e2SPeter Wemm ** Parameters: 1039c2aa98e2SPeter Wemm ** fm -- the from line. 1040a7ec597cSGregory Neil Shapiro ** e -- envelope 1041c2aa98e2SPeter Wemm ** 1042c2aa98e2SPeter Wemm ** Returns: 1043c2aa98e2SPeter Wemm ** none. 1044c2aa98e2SPeter Wemm ** 1045c2aa98e2SPeter Wemm ** Side Effects: 1046c2aa98e2SPeter Wemm ** extracts what information it can from the header, 1047c2aa98e2SPeter Wemm ** such as the date. 1048c2aa98e2SPeter Wemm */ 1049c2aa98e2SPeter Wemm 1050c2aa98e2SPeter Wemm #ifndef NOTUNIX 1051c2aa98e2SPeter Wemm 105206f25ae9SGregory Neil Shapiro static char *DowList[] = 1053c2aa98e2SPeter Wemm { 1054c2aa98e2SPeter Wemm "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 1055c2aa98e2SPeter Wemm }; 1056c2aa98e2SPeter Wemm 105706f25ae9SGregory Neil Shapiro static char *MonthList[] = 1058c2aa98e2SPeter Wemm { 1059c2aa98e2SPeter Wemm "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1060c2aa98e2SPeter Wemm "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 1061c2aa98e2SPeter Wemm NULL 1062c2aa98e2SPeter Wemm }; 1063c2aa98e2SPeter Wemm 106406f25ae9SGregory Neil Shapiro static void 1065c2aa98e2SPeter Wemm eatfrom(fm, e) 1066c2aa98e2SPeter Wemm char *volatile fm; 1067c2aa98e2SPeter Wemm register ENVELOPE *e; 1068c2aa98e2SPeter Wemm { 1069c2aa98e2SPeter Wemm register char *p; 1070c2aa98e2SPeter Wemm register char **dt; 1071c2aa98e2SPeter Wemm 1072c2aa98e2SPeter Wemm if (tTd(30, 2)) 107340266059SGregory Neil Shapiro sm_dprintf("eatfrom(%s)\n", fm); 1074c2aa98e2SPeter Wemm 1075c2aa98e2SPeter Wemm /* find the date part */ 1076c2aa98e2SPeter Wemm p = fm; 1077c2aa98e2SPeter Wemm while (*p != '\0') 1078c2aa98e2SPeter Wemm { 1079c2aa98e2SPeter Wemm /* skip a word */ 1080c2aa98e2SPeter Wemm while (*p != '\0' && *p != ' ') 1081c2aa98e2SPeter Wemm p++; 1082c2aa98e2SPeter Wemm while (*p == ' ') 1083c2aa98e2SPeter Wemm p++; 1084193538b7SGregory Neil Shapiro if (strlen(p) < 17) 1085193538b7SGregory Neil Shapiro { 1086193538b7SGregory Neil Shapiro /* no room for the date */ 1087193538b7SGregory Neil Shapiro return; 1088193538b7SGregory Neil Shapiro } 1089c2aa98e2SPeter Wemm if (!(isascii(*p) && isupper(*p)) || 1090c2aa98e2SPeter Wemm p[3] != ' ' || p[13] != ':' || p[16] != ':') 1091c2aa98e2SPeter Wemm continue; 1092c2aa98e2SPeter Wemm 1093c2aa98e2SPeter Wemm /* we have a possible date */ 1094c2aa98e2SPeter Wemm for (dt = DowList; *dt != NULL; dt++) 1095c2aa98e2SPeter Wemm if (strncmp(*dt, p, 3) == 0) 1096c2aa98e2SPeter Wemm break; 1097c2aa98e2SPeter Wemm if (*dt == NULL) 1098c2aa98e2SPeter Wemm continue; 1099c2aa98e2SPeter Wemm 1100c2aa98e2SPeter Wemm for (dt = MonthList; *dt != NULL; dt++) 1101193538b7SGregory Neil Shapiro { 1102c2aa98e2SPeter Wemm if (strncmp(*dt, &p[4], 3) == 0) 1103c2aa98e2SPeter Wemm break; 1104193538b7SGregory Neil Shapiro } 1105c2aa98e2SPeter Wemm if (*dt != NULL) 1106c2aa98e2SPeter Wemm break; 1107c2aa98e2SPeter Wemm } 1108c2aa98e2SPeter Wemm 1109c2aa98e2SPeter Wemm if (*p != '\0') 1110c2aa98e2SPeter Wemm { 111140266059SGregory Neil Shapiro char *q, buf[25]; 1112c2aa98e2SPeter Wemm 1113c2aa98e2SPeter Wemm /* we have found a date */ 111440266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p, sizeof(buf)); 111540266059SGregory Neil Shapiro q = arpadate(buf); 111640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'a', q); 1117c2aa98e2SPeter Wemm } 1118c2aa98e2SPeter Wemm } 111906f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 1120