1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993 6*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 9*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 10*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <sendmail.h> 17*7c478bd9Sstevel@tonic-gate 18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: collect.c,v 8.261 2005/02/16 23:38:51 ca Exp $") 19*7c478bd9Sstevel@tonic-gate 20*7c478bd9Sstevel@tonic-gate static void collecttimeout __P((int)); 21*7c478bd9Sstevel@tonic-gate static void eatfrom __P((char *volatile, ENVELOPE *)); 22*7c478bd9Sstevel@tonic-gate static void collect_doheader __P((ENVELOPE *)); 23*7c478bd9Sstevel@tonic-gate static SM_FILE_T *collect_dfopen __P((ENVELOPE *)); 24*7c478bd9Sstevel@tonic-gate static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int)); 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate ** COLLECT_EOH -- end-of-header processing in collect() 28*7c478bd9Sstevel@tonic-gate ** 29*7c478bd9Sstevel@tonic-gate ** Called by collect() when it encounters the blank line 30*7c478bd9Sstevel@tonic-gate ** separating the header from the message body, or when it 31*7c478bd9Sstevel@tonic-gate ** encounters EOF in a message that contains only a header. 32*7c478bd9Sstevel@tonic-gate ** 33*7c478bd9Sstevel@tonic-gate ** Parameters: 34*7c478bd9Sstevel@tonic-gate ** e -- envelope 35*7c478bd9Sstevel@tonic-gate ** numhdrs -- number of headers 36*7c478bd9Sstevel@tonic-gate ** hdrslen -- length of headers 37*7c478bd9Sstevel@tonic-gate ** 38*7c478bd9Sstevel@tonic-gate ** Results: 39*7c478bd9Sstevel@tonic-gate ** NULL, or handle to open data file 40*7c478bd9Sstevel@tonic-gate ** 41*7c478bd9Sstevel@tonic-gate ** Side Effects: 42*7c478bd9Sstevel@tonic-gate ** end-of-header check ruleset is invoked. 43*7c478bd9Sstevel@tonic-gate ** envelope state is updated. 44*7c478bd9Sstevel@tonic-gate ** headers may be added and deleted. 45*7c478bd9Sstevel@tonic-gate ** selects the queue. 46*7c478bd9Sstevel@tonic-gate ** opens the data file. 47*7c478bd9Sstevel@tonic-gate */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate static SM_FILE_T * 50*7c478bd9Sstevel@tonic-gate collect_eoh(e, numhdrs, hdrslen) 51*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 52*7c478bd9Sstevel@tonic-gate int numhdrs; 53*7c478bd9Sstevel@tonic-gate int hdrslen; 54*7c478bd9Sstevel@tonic-gate { 55*7c478bd9Sstevel@tonic-gate char hnum[16]; 56*7c478bd9Sstevel@tonic-gate char hsize[16]; 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* call the end-of-header check ruleset */ 59*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs); 60*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen); 61*7c478bd9Sstevel@tonic-gate if (tTd(30, 10)) 62*7c478bd9Sstevel@tonic-gate sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 63*7c478bd9Sstevel@tonic-gate hnum, hsize); 64*7c478bd9Sstevel@tonic-gate (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT, 65*7c478bd9Sstevel@tonic-gate 3, NULL, e->e_id); 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate ** Process the header, 69*7c478bd9Sstevel@tonic-gate ** select the queue, open the data file. 70*7c478bd9Sstevel@tonic-gate */ 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate collect_doheader(e); 73*7c478bd9Sstevel@tonic-gate return collect_dfopen(e); 74*7c478bd9Sstevel@tonic-gate } 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* 77*7c478bd9Sstevel@tonic-gate ** COLLECT_DOHEADER -- process header in collect() 78*7c478bd9Sstevel@tonic-gate ** 79*7c478bd9Sstevel@tonic-gate ** Called by collect() after it has finished parsing the header, 80*7c478bd9Sstevel@tonic-gate ** but before it selects the queue and creates the data file. 81*7c478bd9Sstevel@tonic-gate ** The results of processing the header will affect queue selection. 82*7c478bd9Sstevel@tonic-gate ** 83*7c478bd9Sstevel@tonic-gate ** Parameters: 84*7c478bd9Sstevel@tonic-gate ** e -- envelope 85*7c478bd9Sstevel@tonic-gate ** 86*7c478bd9Sstevel@tonic-gate ** Results: 87*7c478bd9Sstevel@tonic-gate ** none. 88*7c478bd9Sstevel@tonic-gate ** 89*7c478bd9Sstevel@tonic-gate ** Side Effects: 90*7c478bd9Sstevel@tonic-gate ** envelope state is updated. 91*7c478bd9Sstevel@tonic-gate ** headers may be added and deleted. 92*7c478bd9Sstevel@tonic-gate */ 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate static void 95*7c478bd9Sstevel@tonic-gate collect_doheader(e) 96*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 97*7c478bd9Sstevel@tonic-gate { 98*7c478bd9Sstevel@tonic-gate /* 99*7c478bd9Sstevel@tonic-gate ** Find out some information from the headers. 100*7c478bd9Sstevel@tonic-gate ** Examples are who is the from person & the date. 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate eatheader(e, true, false); 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate if (GrabTo && e->e_sendqueue == NULL) 106*7c478bd9Sstevel@tonic-gate usrerr("No recipient addresses found in header"); 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate ** If we have a Return-Receipt-To:, turn it into a DSN. 110*7c478bd9Sstevel@tonic-gate */ 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 113*7c478bd9Sstevel@tonic-gate { 114*7c478bd9Sstevel@tonic-gate ADDRESS *q; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 117*7c478bd9Sstevel@tonic-gate if (!bitset(QHASNOTIFY, q->q_flags)) 118*7c478bd9Sstevel@tonic-gate q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* 122*7c478bd9Sstevel@tonic-gate ** Add an appropriate recipient line if we have none. 123*7c478bd9Sstevel@tonic-gate */ 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate if (hvalue("to", e->e_header) != NULL || 126*7c478bd9Sstevel@tonic-gate hvalue("cc", e->e_header) != NULL || 127*7c478bd9Sstevel@tonic-gate hvalue("apparently-to", e->e_header) != NULL) 128*7c478bd9Sstevel@tonic-gate { 129*7c478bd9Sstevel@tonic-gate /* have a valid recipient header -- delete Bcc: headers */ 130*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DELETE_BCC; 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate else if (hvalue("bcc", e->e_header) == NULL) 133*7c478bd9Sstevel@tonic-gate { 134*7c478bd9Sstevel@tonic-gate /* no valid recipient headers */ 135*7c478bd9Sstevel@tonic-gate register ADDRESS *q; 136*7c478bd9Sstevel@tonic-gate char *hdr = NULL; 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* create a recipient field */ 139*7c478bd9Sstevel@tonic-gate switch (NoRecipientAction) 140*7c478bd9Sstevel@tonic-gate { 141*7c478bd9Sstevel@tonic-gate case NRA_ADD_APPARENTLY_TO: 142*7c478bd9Sstevel@tonic-gate hdr = "Apparently-To"; 143*7c478bd9Sstevel@tonic-gate break; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate case NRA_ADD_TO: 146*7c478bd9Sstevel@tonic-gate hdr = "To"; 147*7c478bd9Sstevel@tonic-gate break; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate case NRA_ADD_BCC: 150*7c478bd9Sstevel@tonic-gate addheader("Bcc", " ", 0, e); 151*7c478bd9Sstevel@tonic-gate break; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate case NRA_ADD_TO_UNDISCLOSED: 154*7c478bd9Sstevel@tonic-gate addheader("To", "undisclosed-recipients:;", 0, e); 155*7c478bd9Sstevel@tonic-gate break; 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate if (hdr != NULL) 159*7c478bd9Sstevel@tonic-gate { 160*7c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate if (q->q_alias != NULL) 163*7c478bd9Sstevel@tonic-gate continue; 164*7c478bd9Sstevel@tonic-gate if (tTd(30, 3)) 165*7c478bd9Sstevel@tonic-gate sm_dprintf("Adding %s: %s\n", 166*7c478bd9Sstevel@tonic-gate hdr, q->q_paddr); 167*7c478bd9Sstevel@tonic-gate addheader(hdr, q->q_paddr, 0, e); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate ** COLLECT_DFOPEN -- open the message data file 175*7c478bd9Sstevel@tonic-gate ** 176*7c478bd9Sstevel@tonic-gate ** Called by collect() after it has finished processing the header. 177*7c478bd9Sstevel@tonic-gate ** Queue selection occurs at this point, possibly based on the 178*7c478bd9Sstevel@tonic-gate ** envelope's recipient list and on header information. 179*7c478bd9Sstevel@tonic-gate ** 180*7c478bd9Sstevel@tonic-gate ** Parameters: 181*7c478bd9Sstevel@tonic-gate ** e -- envelope 182*7c478bd9Sstevel@tonic-gate ** 183*7c478bd9Sstevel@tonic-gate ** Results: 184*7c478bd9Sstevel@tonic-gate ** NULL, or a pointer to an open data file, 185*7c478bd9Sstevel@tonic-gate ** into which the message body will be written by collect(). 186*7c478bd9Sstevel@tonic-gate ** 187*7c478bd9Sstevel@tonic-gate ** Side Effects: 188*7c478bd9Sstevel@tonic-gate ** Calls syserr, sets EF_FATALERRS and returns NULL 189*7c478bd9Sstevel@tonic-gate ** if there is insufficient disk space. 190*7c478bd9Sstevel@tonic-gate ** Aborts process if data file could not be opened. 191*7c478bd9Sstevel@tonic-gate ** Otherwise, the queue is selected, 192*7c478bd9Sstevel@tonic-gate ** e->e_{dfino,dfdev,msgsize,flags} are updated, 193*7c478bd9Sstevel@tonic-gate ** and a pointer to an open data file is returned. 194*7c478bd9Sstevel@tonic-gate */ 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate static SM_FILE_T * 197*7c478bd9Sstevel@tonic-gate collect_dfopen(e) 198*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 199*7c478bd9Sstevel@tonic-gate { 200*7c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 201*7c478bd9Sstevel@tonic-gate int dfd; 202*7c478bd9Sstevel@tonic-gate struct stat stbuf; 203*7c478bd9Sstevel@tonic-gate SM_FILE_T *df; 204*7c478bd9Sstevel@tonic-gate char *dfname; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate if (!setnewqueue(e)) 207*7c478bd9Sstevel@tonic-gate return NULL; 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate dfname = queuename(e, DATAFL_LETTER); 210*7c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 211*7c478bd9Sstevel@tonic-gate oldumask = umask(002); 212*7c478bd9Sstevel@tonic-gate df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 213*7c478bd9Sstevel@tonic-gate SFF_OPENASROOT); 214*7c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 215*7c478bd9Sstevel@tonic-gate (void) umask(oldumask); 216*7c478bd9Sstevel@tonic-gate if (df == NULL) 217*7c478bd9Sstevel@tonic-gate { 218*7c478bd9Sstevel@tonic-gate syserr("@Cannot create %s", dfname); 219*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 220*7c478bd9Sstevel@tonic-gate flush_errors(true); 221*7c478bd9Sstevel@tonic-gate finis(false, true, ExitStat); 222*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 225*7c478bd9Sstevel@tonic-gate if (dfd < 0 || fstat(dfd, &stbuf) < 0) 226*7c478bd9Sstevel@tonic-gate e->e_dfino = -1; 227*7c478bd9Sstevel@tonic-gate else 228*7c478bd9Sstevel@tonic-gate { 229*7c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev; 230*7c478bd9Sstevel@tonic-gate e->e_dfino = stbuf.st_ino; 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 233*7c478bd9Sstevel@tonic-gate return df; 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate ** COLLECT -- read & parse message header & make temp file. 238*7c478bd9Sstevel@tonic-gate ** 239*7c478bd9Sstevel@tonic-gate ** Creates a temporary file name and copies the standard 240*7c478bd9Sstevel@tonic-gate ** input to that file. Leading UNIX-style "From" lines are 241*7c478bd9Sstevel@tonic-gate ** stripped off (after important information is extracted). 242*7c478bd9Sstevel@tonic-gate ** 243*7c478bd9Sstevel@tonic-gate ** Parameters: 244*7c478bd9Sstevel@tonic-gate ** fp -- file to read. 245*7c478bd9Sstevel@tonic-gate ** smtpmode -- if set, we are running SMTP: give an RFC821 246*7c478bd9Sstevel@tonic-gate ** style message to say we are ready to collect 247*7c478bd9Sstevel@tonic-gate ** input, and never ignore a single dot to mean 248*7c478bd9Sstevel@tonic-gate ** end of message. 249*7c478bd9Sstevel@tonic-gate ** hdrp -- the location to stash the header. 250*7c478bd9Sstevel@tonic-gate ** e -- the current envelope. 251*7c478bd9Sstevel@tonic-gate ** rsetsize -- reset e_msgsize? 252*7c478bd9Sstevel@tonic-gate ** 253*7c478bd9Sstevel@tonic-gate ** Returns: 254*7c478bd9Sstevel@tonic-gate ** none. 255*7c478bd9Sstevel@tonic-gate ** 256*7c478bd9Sstevel@tonic-gate ** Side Effects: 257*7c478bd9Sstevel@tonic-gate ** If successful, 258*7c478bd9Sstevel@tonic-gate ** - Data file is created and filled, and e->e_dfp is set. 259*7c478bd9Sstevel@tonic-gate ** - The from person may be set. 260*7c478bd9Sstevel@tonic-gate ** If the "enough disk space" check fails, 261*7c478bd9Sstevel@tonic-gate ** - syserr is called. 262*7c478bd9Sstevel@tonic-gate ** - e->e_dfp is NULL. 263*7c478bd9Sstevel@tonic-gate ** - e->e_flags & EF_FATALERRS is set. 264*7c478bd9Sstevel@tonic-gate ** - collect() returns. 265*7c478bd9Sstevel@tonic-gate ** If data file cannot be created, the process is terminated. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate static jmp_buf CtxCollectTimeout; 269*7c478bd9Sstevel@tonic-gate static bool volatile CollectProgress; 270*7c478bd9Sstevel@tonic-gate static SM_EVENT *volatile CollectTimeout = NULL; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* values for input state machine */ 273*7c478bd9Sstevel@tonic-gate #define IS_NORM 0 /* middle of line */ 274*7c478bd9Sstevel@tonic-gate #define IS_BOL 1 /* beginning of line */ 275*7c478bd9Sstevel@tonic-gate #define IS_DOT 2 /* read a dot at beginning of line */ 276*7c478bd9Sstevel@tonic-gate #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 277*7c478bd9Sstevel@tonic-gate #define IS_CR 4 /* read a carriage return */ 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate /* values for message state machine */ 280*7c478bd9Sstevel@tonic-gate #define MS_UFROM 0 /* reading Unix from line */ 281*7c478bd9Sstevel@tonic-gate #define MS_HEADER 1 /* reading message header */ 282*7c478bd9Sstevel@tonic-gate #define MS_BODY 2 /* reading message body */ 283*7c478bd9Sstevel@tonic-gate #define MS_DISCARD 3 /* discarding rest of message */ 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate void 286*7c478bd9Sstevel@tonic-gate collect(fp, smtpmode, hdrp, e, rsetsize) 287*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp; 288*7c478bd9Sstevel@tonic-gate bool smtpmode; 289*7c478bd9Sstevel@tonic-gate HDR **hdrp; 290*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 291*7c478bd9Sstevel@tonic-gate bool rsetsize; 292*7c478bd9Sstevel@tonic-gate { 293*7c478bd9Sstevel@tonic-gate register SM_FILE_T *volatile df; 294*7c478bd9Sstevel@tonic-gate volatile bool ignrdot; 295*7c478bd9Sstevel@tonic-gate volatile int dbto; 296*7c478bd9Sstevel@tonic-gate register char *volatile bp; 297*7c478bd9Sstevel@tonic-gate volatile int c; 298*7c478bd9Sstevel@tonic-gate volatile bool inputerr; 299*7c478bd9Sstevel@tonic-gate bool headeronly; 300*7c478bd9Sstevel@tonic-gate char *volatile buf; 301*7c478bd9Sstevel@tonic-gate volatile int buflen; 302*7c478bd9Sstevel@tonic-gate volatile int istate; 303*7c478bd9Sstevel@tonic-gate volatile int mstate; 304*7c478bd9Sstevel@tonic-gate volatile int hdrslen; 305*7c478bd9Sstevel@tonic-gate volatile int numhdrs; 306*7c478bd9Sstevel@tonic-gate volatile int afd; 307*7c478bd9Sstevel@tonic-gate unsigned char *volatile pbp; 308*7c478bd9Sstevel@tonic-gate unsigned char peekbuf[8]; 309*7c478bd9Sstevel@tonic-gate char bufbuf[MAXLINE]; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate df = NULL; 312*7c478bd9Sstevel@tonic-gate ignrdot = smtpmode ? false : IgnrDot; 313*7c478bd9Sstevel@tonic-gate dbto = smtpmode ? (int) TimeOuts.to_datablock : 0; 314*7c478bd9Sstevel@tonic-gate c = SM_IO_EOF; 315*7c478bd9Sstevel@tonic-gate inputerr = false; 316*7c478bd9Sstevel@tonic-gate headeronly = hdrp != NULL; 317*7c478bd9Sstevel@tonic-gate hdrslen = 0; 318*7c478bd9Sstevel@tonic-gate numhdrs = 0; 319*7c478bd9Sstevel@tonic-gate HasEightBits = false; 320*7c478bd9Sstevel@tonic-gate buf = bp = bufbuf; 321*7c478bd9Sstevel@tonic-gate buflen = sizeof bufbuf; 322*7c478bd9Sstevel@tonic-gate pbp = peekbuf; 323*7c478bd9Sstevel@tonic-gate istate = IS_BOL; 324*7c478bd9Sstevel@tonic-gate mstate = SaveFrom ? MS_HEADER : MS_UFROM; 325*7c478bd9Sstevel@tonic-gate CollectProgress = false; 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate ** Tell ARPANET to go ahead. 329*7c478bd9Sstevel@tonic-gate */ 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate if (smtpmode) 332*7c478bd9Sstevel@tonic-gate message("354 Enter mail, end with \".\" on a line by itself"); 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate if (tTd(30, 2)) 335*7c478bd9Sstevel@tonic-gate sm_dprintf("collect\n"); 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate ** Read the message. 339*7c478bd9Sstevel@tonic-gate ** 340*7c478bd9Sstevel@tonic-gate ** This is done using two interleaved state machines. 341*7c478bd9Sstevel@tonic-gate ** The input state machine is looking for things like 342*7c478bd9Sstevel@tonic-gate ** hidden dots; the message state machine is handling 343*7c478bd9Sstevel@tonic-gate ** the larger picture (e.g., header versus body). 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate if (dbto != 0) 347*7c478bd9Sstevel@tonic-gate { 348*7c478bd9Sstevel@tonic-gate /* handle possible input timeout */ 349*7c478bd9Sstevel@tonic-gate if (setjmp(CtxCollectTimeout) != 0) 350*7c478bd9Sstevel@tonic-gate { 351*7c478bd9Sstevel@tonic-gate if (LogLevel > 2) 352*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 353*7c478bd9Sstevel@tonic-gate "timeout waiting for input from %s during message collect", 354*7c478bd9Sstevel@tonic-gate CURHOSTNAME); 355*7c478bd9Sstevel@tonic-gate errno = 0; 356*7c478bd9Sstevel@tonic-gate if (smtpmode) 357*7c478bd9Sstevel@tonic-gate { 358*7c478bd9Sstevel@tonic-gate /* 359*7c478bd9Sstevel@tonic-gate ** Override e_message in usrerr() as this 360*7c478bd9Sstevel@tonic-gate ** is the reason for failure that should 361*7c478bd9Sstevel@tonic-gate ** be logged for undelivered recipients. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate e->e_message = NULL; 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate usrerr("451 4.4.1 timeout waiting for input during message collect"); 367*7c478bd9Sstevel@tonic-gate goto readerr; 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate CollectTimeout = sm_setevent(dbto, collecttimeout, dbto); 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (rsetsize) 373*7c478bd9Sstevel@tonic-gate e->e_msgsize = 0; 374*7c478bd9Sstevel@tonic-gate for (;;) 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate if (tTd(30, 35)) 377*7c478bd9Sstevel@tonic-gate sm_dprintf("top, istate=%d, mstate=%d\n", istate, 378*7c478bd9Sstevel@tonic-gate mstate); 379*7c478bd9Sstevel@tonic-gate for (;;) 380*7c478bd9Sstevel@tonic-gate { 381*7c478bd9Sstevel@tonic-gate if (pbp > peekbuf) 382*7c478bd9Sstevel@tonic-gate c = *--pbp; 383*7c478bd9Sstevel@tonic-gate else 384*7c478bd9Sstevel@tonic-gate { 385*7c478bd9Sstevel@tonic-gate while (!sm_io_eof(fp) && !sm_io_error(fp)) 386*7c478bd9Sstevel@tonic-gate { 387*7c478bd9Sstevel@tonic-gate errno = 0; 388*7c478bd9Sstevel@tonic-gate c = sm_io_getc(fp, SM_TIME_DEFAULT); 389*7c478bd9Sstevel@tonic-gate if (c == SM_IO_EOF && errno == EINTR) 390*7c478bd9Sstevel@tonic-gate { 391*7c478bd9Sstevel@tonic-gate /* Interrupted, retry */ 392*7c478bd9Sstevel@tonic-gate sm_io_clearerr(fp); 393*7c478bd9Sstevel@tonic-gate continue; 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate break; 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate CollectProgress = true; 398*7c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL && !headeronly) 399*7c478bd9Sstevel@tonic-gate { 400*7c478bd9Sstevel@tonic-gate if (istate == IS_BOL) 401*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 402*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 403*7c478bd9Sstevel@tonic-gate "%05d <<< ", 404*7c478bd9Sstevel@tonic-gate (int) CurrentPid); 405*7c478bd9Sstevel@tonic-gate if (c == SM_IO_EOF) 406*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 407*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 408*7c478bd9Sstevel@tonic-gate "[EOF]\n"); 409*7c478bd9Sstevel@tonic-gate else 410*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 411*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 412*7c478bd9Sstevel@tonic-gate c); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate if (c == SM_IO_EOF) 415*7c478bd9Sstevel@tonic-gate goto readerr; 416*7c478bd9Sstevel@tonic-gate if (SevenBitInput) 417*7c478bd9Sstevel@tonic-gate c &= 0x7f; 418*7c478bd9Sstevel@tonic-gate else 419*7c478bd9Sstevel@tonic-gate HasEightBits |= bitset(0x80, c); 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate if (tTd(30, 94)) 422*7c478bd9Sstevel@tonic-gate sm_dprintf("istate=%d, c=%c (0x%x)\n", 423*7c478bd9Sstevel@tonic-gate istate, (char) c, c); 424*7c478bd9Sstevel@tonic-gate switch (istate) 425*7c478bd9Sstevel@tonic-gate { 426*7c478bd9Sstevel@tonic-gate case IS_BOL: 427*7c478bd9Sstevel@tonic-gate if (c == '.') 428*7c478bd9Sstevel@tonic-gate { 429*7c478bd9Sstevel@tonic-gate istate = IS_DOT; 430*7c478bd9Sstevel@tonic-gate continue; 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate break; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate case IS_DOT: 435*7c478bd9Sstevel@tonic-gate if (c == '\n' && !ignrdot && 436*7c478bd9Sstevel@tonic-gate !bitset(EF_NL_NOT_EOL, e->e_flags)) 437*7c478bd9Sstevel@tonic-gate goto readerr; 438*7c478bd9Sstevel@tonic-gate else if (c == '\r' && 439*7c478bd9Sstevel@tonic-gate !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 440*7c478bd9Sstevel@tonic-gate { 441*7c478bd9Sstevel@tonic-gate istate = IS_DOTCR; 442*7c478bd9Sstevel@tonic-gate continue; 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate else if (ignrdot || 445*7c478bd9Sstevel@tonic-gate (c != '.' && 446*7c478bd9Sstevel@tonic-gate OpMode != MD_SMTP && 447*7c478bd9Sstevel@tonic-gate OpMode != MD_DAEMON && 448*7c478bd9Sstevel@tonic-gate OpMode != MD_ARPAFTP)) 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate { 451*7c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 452*7c478bd9Sstevel@tonic-gate *pbp++ = c; 453*7c478bd9Sstevel@tonic-gate c = '.'; 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate break; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate case IS_DOTCR: 458*7c478bd9Sstevel@tonic-gate if (c == '\n' && !ignrdot) 459*7c478bd9Sstevel@tonic-gate goto readerr; 460*7c478bd9Sstevel@tonic-gate else 461*7c478bd9Sstevel@tonic-gate { 462*7c478bd9Sstevel@tonic-gate /* push back the ".\rx" */ 463*7c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 464*7c478bd9Sstevel@tonic-gate *pbp++ = c; 465*7c478bd9Sstevel@tonic-gate if (OpMode != MD_SMTP && 466*7c478bd9Sstevel@tonic-gate OpMode != MD_DAEMON && 467*7c478bd9Sstevel@tonic-gate OpMode != MD_ARPAFTP) 468*7c478bd9Sstevel@tonic-gate { 469*7c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 470*7c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 471*7c478bd9Sstevel@tonic-gate *pbp++ = '\r'; 472*7c478bd9Sstevel@tonic-gate c = '.'; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate else 475*7c478bd9Sstevel@tonic-gate c = '\r'; 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate break; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate case IS_CR: 480*7c478bd9Sstevel@tonic-gate if (c == '\n') 481*7c478bd9Sstevel@tonic-gate istate = IS_BOL; 482*7c478bd9Sstevel@tonic-gate else 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 485*7c478bd9Sstevel@tonic-gate c); 486*7c478bd9Sstevel@tonic-gate c = '\r'; 487*7c478bd9Sstevel@tonic-gate istate = IS_NORM; 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate goto bufferchar; 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate istate = IS_CR; 495*7c478bd9Sstevel@tonic-gate continue; 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate else if (c == '\n' && !bitset(EF_NL_NOT_EOL, 498*7c478bd9Sstevel@tonic-gate e->e_flags)) 499*7c478bd9Sstevel@tonic-gate istate = IS_BOL; 500*7c478bd9Sstevel@tonic-gate else 501*7c478bd9Sstevel@tonic-gate istate = IS_NORM; 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate bufferchar: 504*7c478bd9Sstevel@tonic-gate if (!headeronly) 505*7c478bd9Sstevel@tonic-gate { 506*7c478bd9Sstevel@tonic-gate /* no overflow? */ 507*7c478bd9Sstevel@tonic-gate if (e->e_msgsize >= 0) 508*7c478bd9Sstevel@tonic-gate { 509*7c478bd9Sstevel@tonic-gate e->e_msgsize++; 510*7c478bd9Sstevel@tonic-gate if (MaxMessageSize > 0 && 511*7c478bd9Sstevel@tonic-gate !bitset(EF_TOOBIG, e->e_flags) && 512*7c478bd9Sstevel@tonic-gate e->e_msgsize > MaxMessageSize) 513*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_TOOBIG; 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate switch (mstate) 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate case MS_BODY: 519*7c478bd9Sstevel@tonic-gate /* just put the character out */ 520*7c478bd9Sstevel@tonic-gate if (!bitset(EF_TOOBIG, e->e_flags)) 521*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(df, SM_TIME_DEFAULT, 522*7c478bd9Sstevel@tonic-gate c); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate case MS_DISCARD: 527*7c478bd9Sstevel@tonic-gate continue; 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate SM_ASSERT(mstate == MS_UFROM || mstate == MS_HEADER); 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate /* header -- buffer up */ 533*7c478bd9Sstevel@tonic-gate if (bp >= &buf[buflen - 2]) 534*7c478bd9Sstevel@tonic-gate { 535*7c478bd9Sstevel@tonic-gate char *obuf; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* out of space for header */ 538*7c478bd9Sstevel@tonic-gate obuf = buf; 539*7c478bd9Sstevel@tonic-gate if (buflen < MEMCHUNKSIZE) 540*7c478bd9Sstevel@tonic-gate buflen *= 2; 541*7c478bd9Sstevel@tonic-gate else 542*7c478bd9Sstevel@tonic-gate buflen += MEMCHUNKSIZE; 543*7c478bd9Sstevel@tonic-gate buf = xalloc(buflen); 544*7c478bd9Sstevel@tonic-gate memmove(buf, obuf, bp - obuf); 545*7c478bd9Sstevel@tonic-gate bp = &buf[bp - obuf]; 546*7c478bd9Sstevel@tonic-gate if (obuf != bufbuf) 547*7c478bd9Sstevel@tonic-gate sm_free(obuf); /* XXX */ 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate ** XXX Notice: the logic here is broken. 552*7c478bd9Sstevel@tonic-gate ** An input to sendmail that doesn't contain a 553*7c478bd9Sstevel@tonic-gate ** header but starts immediately with the body whose 554*7c478bd9Sstevel@tonic-gate ** first line contain characters which match the 555*7c478bd9Sstevel@tonic-gate ** following "if" will cause problems: those 556*7c478bd9Sstevel@tonic-gate ** characters will NOT appear in the output... 557*7c478bd9Sstevel@tonic-gate ** Do we care? 558*7c478bd9Sstevel@tonic-gate */ 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate if (c >= 0200 && c <= 0237) 561*7c478bd9Sstevel@tonic-gate { 562*7c478bd9Sstevel@tonic-gate #if 0 /* causes complaints -- figure out something for 8.n+1 */ 563*7c478bd9Sstevel@tonic-gate usrerr("Illegal character 0x%x in header", c); 564*7c478bd9Sstevel@tonic-gate #else /* 0 */ 565*7c478bd9Sstevel@tonic-gate /* EMPTY */ 566*7c478bd9Sstevel@tonic-gate #endif /* 0 */ 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate else if (c != '\0') 569*7c478bd9Sstevel@tonic-gate { 570*7c478bd9Sstevel@tonic-gate *bp++ = c; 571*7c478bd9Sstevel@tonic-gate ++hdrslen; 572*7c478bd9Sstevel@tonic-gate if (!headeronly && 573*7c478bd9Sstevel@tonic-gate MaxHeadersLength > 0 && 574*7c478bd9Sstevel@tonic-gate hdrslen > MaxHeadersLength) 575*7c478bd9Sstevel@tonic-gate { 576*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 577*7c478bd9Sstevel@tonic-gate "headers too large (%d max) from %s during message collect", 578*7c478bd9Sstevel@tonic-gate MaxHeadersLength, 579*7c478bd9Sstevel@tonic-gate CURHOSTNAME); 580*7c478bd9Sstevel@tonic-gate errno = 0; 581*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 582*7c478bd9Sstevel@tonic-gate e->e_status = "5.6.0"; 583*7c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 584*7c478bd9Sstevel@tonic-gate "552 Headers too large (%d max)", 585*7c478bd9Sstevel@tonic-gate MaxHeadersLength); 586*7c478bd9Sstevel@tonic-gate mstate = MS_DISCARD; 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate if (istate == IS_BOL) 590*7c478bd9Sstevel@tonic-gate break; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate *bp = '\0'; 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate nextstate: 595*7c478bd9Sstevel@tonic-gate if (tTd(30, 35)) 596*7c478bd9Sstevel@tonic-gate sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 597*7c478bd9Sstevel@tonic-gate istate, mstate, buf); 598*7c478bd9Sstevel@tonic-gate switch (mstate) 599*7c478bd9Sstevel@tonic-gate { 600*7c478bd9Sstevel@tonic-gate case MS_UFROM: 601*7c478bd9Sstevel@tonic-gate mstate = MS_HEADER; 602*7c478bd9Sstevel@tonic-gate #ifndef NOTUNIX 603*7c478bd9Sstevel@tonic-gate if (strncmp(buf, "From ", 5) == 0) 604*7c478bd9Sstevel@tonic-gate { 605*7c478bd9Sstevel@tonic-gate bp = buf; 606*7c478bd9Sstevel@tonic-gate eatfrom(buf, e); 607*7c478bd9Sstevel@tonic-gate continue; 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate #endif /* ! NOTUNIX */ 610*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate case MS_HEADER: 613*7c478bd9Sstevel@tonic-gate if (!isheader(buf)) 614*7c478bd9Sstevel@tonic-gate { 615*7c478bd9Sstevel@tonic-gate mstate = MS_BODY; 616*7c478bd9Sstevel@tonic-gate goto nextstate; 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate /* check for possible continuation line */ 620*7c478bd9Sstevel@tonic-gate do 621*7c478bd9Sstevel@tonic-gate { 622*7c478bd9Sstevel@tonic-gate sm_io_clearerr(fp); 623*7c478bd9Sstevel@tonic-gate errno = 0; 624*7c478bd9Sstevel@tonic-gate c = sm_io_getc(fp, SM_TIME_DEFAULT); 625*7c478bd9Sstevel@tonic-gate } while (c == SM_IO_EOF && errno == EINTR); 626*7c478bd9Sstevel@tonic-gate if (c != SM_IO_EOF) 627*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 628*7c478bd9Sstevel@tonic-gate if (c == ' ' || c == '\t') 629*7c478bd9Sstevel@tonic-gate { 630*7c478bd9Sstevel@tonic-gate /* yep -- defer this */ 631*7c478bd9Sstevel@tonic-gate continue; 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* trim off trailing CRLF or NL */ 635*7c478bd9Sstevel@tonic-gate SM_ASSERT(bp > buf); 636*7c478bd9Sstevel@tonic-gate if (*--bp != '\n' || *--bp != '\r') 637*7c478bd9Sstevel@tonic-gate bp++; 638*7c478bd9Sstevel@tonic-gate *bp = '\0'; 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate if (bitset(H_EOH, chompheader(buf, 641*7c478bd9Sstevel@tonic-gate CHHDR_CHECK | CHHDR_USER, 642*7c478bd9Sstevel@tonic-gate hdrp, e))) 643*7c478bd9Sstevel@tonic-gate { 644*7c478bd9Sstevel@tonic-gate mstate = MS_BODY; 645*7c478bd9Sstevel@tonic-gate goto nextstate; 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate numhdrs++; 648*7c478bd9Sstevel@tonic-gate break; 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate case MS_BODY: 651*7c478bd9Sstevel@tonic-gate if (tTd(30, 1)) 652*7c478bd9Sstevel@tonic-gate sm_dprintf("EOH\n"); 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate if (headeronly) 655*7c478bd9Sstevel@tonic-gate goto readerr; 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate df = collect_eoh(e, numhdrs, hdrslen); 658*7c478bd9Sstevel@tonic-gate if (df == NULL) 659*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_TOOBIG; 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate bp = buf; 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate /* toss blank line */ 664*7c478bd9Sstevel@tonic-gate if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 665*7c478bd9Sstevel@tonic-gate bp[0] == '\r' && bp[1] == '\n') || 666*7c478bd9Sstevel@tonic-gate (!bitset(EF_NL_NOT_EOL, e->e_flags) && 667*7c478bd9Sstevel@tonic-gate bp[0] == '\n')) 668*7c478bd9Sstevel@tonic-gate { 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate /* if not a blank separator, write it out */ 673*7c478bd9Sstevel@tonic-gate if (!bitset(EF_TOOBIG, e->e_flags)) 674*7c478bd9Sstevel@tonic-gate { 675*7c478bd9Sstevel@tonic-gate while (*bp != '\0') 676*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(df, SM_TIME_DEFAULT, 677*7c478bd9Sstevel@tonic-gate *bp++); 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate break; 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate bp = buf; 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate readerr: 685*7c478bd9Sstevel@tonic-gate if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 686*7c478bd9Sstevel@tonic-gate { 687*7c478bd9Sstevel@tonic-gate const char *errmsg; 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate if (sm_io_eof(fp)) 690*7c478bd9Sstevel@tonic-gate errmsg = "unexpected close"; 691*7c478bd9Sstevel@tonic-gate else 692*7c478bd9Sstevel@tonic-gate errmsg = sm_errstring(errno); 693*7c478bd9Sstevel@tonic-gate if (tTd(30, 1)) 694*7c478bd9Sstevel@tonic-gate sm_dprintf("collect: premature EOM: %s\n", errmsg); 695*7c478bd9Sstevel@tonic-gate if (LogLevel > 1) 696*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 697*7c478bd9Sstevel@tonic-gate "collect: premature EOM: %s", errmsg); 698*7c478bd9Sstevel@tonic-gate inputerr = true; 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate /* reset global timer */ 702*7c478bd9Sstevel@tonic-gate if (CollectTimeout != NULL) 703*7c478bd9Sstevel@tonic-gate sm_clrevent(CollectTimeout); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate if (headeronly) 706*7c478bd9Sstevel@tonic-gate return; 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate if (mstate != MS_BODY) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate /* no body or discard, so we never opened the data file */ 711*7c478bd9Sstevel@tonic-gate SM_ASSERT(df == NULL); 712*7c478bd9Sstevel@tonic-gate df = collect_eoh(e, numhdrs, hdrslen); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate if (df == NULL) 716*7c478bd9Sstevel@tonic-gate { 717*7c478bd9Sstevel@tonic-gate /* skip next few clauses */ 718*7c478bd9Sstevel@tonic-gate /* EMPTY */ 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 721*7c478bd9Sstevel@tonic-gate { 722*7c478bd9Sstevel@tonic-gate dferror(df, "sm_io_flush||sm_io_error", e); 723*7c478bd9Sstevel@tonic-gate flush_errors(true); 724*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 725*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate else if (SuperSafe == SAFE_NO || 728*7c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE || 729*7c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode)) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate /* skip next few clauses */ 732*7c478bd9Sstevel@tonic-gate /* EMPTY */ 733*7c478bd9Sstevel@tonic-gate /* Note: updfs() is not called in this case! */ 734*7c478bd9Sstevel@tonic-gate } 735*7c478bd9Sstevel@tonic-gate else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) 736*7c478bd9Sstevel@tonic-gate { 737*7c478bd9Sstevel@tonic-gate int save_errno = errno; 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate if (save_errno == EEXIST) 740*7c478bd9Sstevel@tonic-gate { 741*7c478bd9Sstevel@tonic-gate char *dfile; 742*7c478bd9Sstevel@tonic-gate struct stat st; 743*7c478bd9Sstevel@tonic-gate int dfd; 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate dfile = queuename(e, DATAFL_LETTER); 746*7c478bd9Sstevel@tonic-gate if (stat(dfile, &st) < 0) 747*7c478bd9Sstevel@tonic-gate st.st_size = -1; 748*7c478bd9Sstevel@tonic-gate errno = EEXIST; 749*7c478bd9Sstevel@tonic-gate syserr("@collect: bfcommit(%s): already on disk, size=%ld", 750*7c478bd9Sstevel@tonic-gate dfile, (long) st.st_size); 751*7c478bd9Sstevel@tonic-gate dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 752*7c478bd9Sstevel@tonic-gate if (dfd >= 0) 753*7c478bd9Sstevel@tonic-gate dumpfd(dfd, true, true); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate errno = save_errno; 756*7c478bd9Sstevel@tonic-gate dferror(df, "bfcommit", e); 757*7c478bd9Sstevel@tonic-gate flush_errors(true); 758*7c478bd9Sstevel@tonic-gate finis(save_errno != EEXIST, true, ExitStat); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) 761*7c478bd9Sstevel@tonic-gate { 762*7c478bd9Sstevel@tonic-gate dferror(df, "sm_io_getinfo", e); 763*7c478bd9Sstevel@tonic-gate flush_errors(true); 764*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 765*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate else if (fsync(afd) < 0) 768*7c478bd9Sstevel@tonic-gate { 769*7c478bd9Sstevel@tonic-gate dferror(df, "fsync", e); 770*7c478bd9Sstevel@tonic-gate flush_errors(true); 771*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 772*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 775*7c478bd9Sstevel@tonic-gate { 776*7c478bd9Sstevel@tonic-gate dferror(df, "sm_io_close", e); 777*7c478bd9Sstevel@tonic-gate flush_errors(true); 778*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 779*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate else 782*7c478bd9Sstevel@tonic-gate { 783*7c478bd9Sstevel@tonic-gate /* everything is happily flushed to disk */ 784*7c478bd9Sstevel@tonic-gate df = NULL; 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate /* remove from available space in filesystem */ 787*7c478bd9Sstevel@tonic-gate updfs(e, 0, 1, "collect"); 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate /* An EOF when running SMTP is an error */ 791*7c478bd9Sstevel@tonic-gate if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 792*7c478bd9Sstevel@tonic-gate { 793*7c478bd9Sstevel@tonic-gate char *host; 794*7c478bd9Sstevel@tonic-gate char *problem; 795*7c478bd9Sstevel@tonic-gate ADDRESS *q; 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate host = RealHostName; 798*7c478bd9Sstevel@tonic-gate if (host == NULL) 799*7c478bd9Sstevel@tonic-gate host = "localhost"; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate if (sm_io_eof(fp)) 802*7c478bd9Sstevel@tonic-gate problem = "unexpected close"; 803*7c478bd9Sstevel@tonic-gate else if (sm_io_error(fp)) 804*7c478bd9Sstevel@tonic-gate problem = "I/O error"; 805*7c478bd9Sstevel@tonic-gate else 806*7c478bd9Sstevel@tonic-gate problem = "read timeout"; 807*7c478bd9Sstevel@tonic-gate if (LogLevel > 0 && sm_io_eof(fp)) 808*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 809*7c478bd9Sstevel@tonic-gate "collect: %s on connection from %.100s, sender=%s", 810*7c478bd9Sstevel@tonic-gate problem, host, 811*7c478bd9Sstevel@tonic-gate shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 812*7c478bd9Sstevel@tonic-gate if (sm_io_eof(fp)) 813*7c478bd9Sstevel@tonic-gate usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 814*7c478bd9Sstevel@tonic-gate problem, host, 815*7c478bd9Sstevel@tonic-gate shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 816*7c478bd9Sstevel@tonic-gate else 817*7c478bd9Sstevel@tonic-gate syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 818*7c478bd9Sstevel@tonic-gate problem, host, 819*7c478bd9Sstevel@tonic-gate shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate /* don't return an error indication */ 822*7c478bd9Sstevel@tonic-gate e->e_to = NULL; 823*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_FATALERRS; 824*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate /* Don't send any message notification to sender */ 827*7c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 828*7c478bd9Sstevel@tonic-gate { 829*7c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 830*7c478bd9Sstevel@tonic-gate continue; 831*7c478bd9Sstevel@tonic-gate q->q_state = QS_FATALERR; 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 835*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* Log collection information. */ 839*7c478bd9Sstevel@tonic-gate if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 840*7c478bd9Sstevel@tonic-gate { 841*7c478bd9Sstevel@tonic-gate logsender(e, e->e_msgid); 842*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_LOGSENDER; 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate /* check for message too large */ 846*7c478bd9Sstevel@tonic-gate if (bitset(EF_TOOBIG, e->e_flags)) 847*7c478bd9Sstevel@tonic-gate { 848*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 849*7c478bd9Sstevel@tonic-gate if (!bitset(EF_FATALERRS, e->e_flags)) 850*7c478bd9Sstevel@tonic-gate { 851*7c478bd9Sstevel@tonic-gate e->e_status = "5.2.3"; 852*7c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 853*7c478bd9Sstevel@tonic-gate "552 Message exceeds maximum fixed size (%ld)", 854*7c478bd9Sstevel@tonic-gate MaxMessageSize); 855*7c478bd9Sstevel@tonic-gate if (LogLevel > 6) 856*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 857*7c478bd9Sstevel@tonic-gate "message size (%ld) exceeds maximum (%ld)", 858*7c478bd9Sstevel@tonic-gate e->e_msgsize, MaxMessageSize); 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate /* check for illegal 8-bit data */ 863*7c478bd9Sstevel@tonic-gate if (HasEightBits) 864*7c478bd9Sstevel@tonic-gate { 865*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS8BIT; 866*7c478bd9Sstevel@tonic-gate if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 867*7c478bd9Sstevel@tonic-gate !bitset(EF_IS_MIME, e->e_flags)) 868*7c478bd9Sstevel@tonic-gate { 869*7c478bd9Sstevel@tonic-gate e->e_status = "5.6.1"; 870*7c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, "554 Eight bit data not allowed"); 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate else 874*7c478bd9Sstevel@tonic-gate { 875*7c478bd9Sstevel@tonic-gate /* if it claimed to be 8 bits, well, it lied.... */ 876*7c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL && 877*7c478bd9Sstevel@tonic-gate sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 878*7c478bd9Sstevel@tonic-gate e->e_bodytype = "7BIT"; 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 882*7c478bd9Sstevel@tonic-gate { 883*7c478bd9Sstevel@tonic-gate char *dfname = queuename(e, DATAFL_LETTER); 884*7c478bd9Sstevel@tonic-gate if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 885*7c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL)) == NULL) 886*7c478bd9Sstevel@tonic-gate { 887*7c478bd9Sstevel@tonic-gate /* we haven't acked receipt yet, so just chuck this */ 888*7c478bd9Sstevel@tonic-gate syserr("@Cannot reopen %s", dfname); 889*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 890*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate else 894*7c478bd9Sstevel@tonic-gate e->e_dfp = df; 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* collect statistics */ 897*7c478bd9Sstevel@tonic-gate if (OpMode != MD_VERIFY) 898*7c478bd9Sstevel@tonic-gate { 899*7c478bd9Sstevel@tonic-gate /* 900*7c478bd9Sstevel@tonic-gate ** Recalculate e_msgpriority, it is done at in eatheader() 901*7c478bd9Sstevel@tonic-gate ** which is called (in 8.12) after the header is collected, 902*7c478bd9Sstevel@tonic-gate ** hence e_msgsize is (most likely) incorrect. 903*7c478bd9Sstevel@tonic-gate */ 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate e->e_msgpriority = e->e_msgsize 906*7c478bd9Sstevel@tonic-gate - e->e_class * WkClassFact 907*7c478bd9Sstevel@tonic-gate + e->e_nrcpts * WkRecipFact; 908*7c478bd9Sstevel@tonic-gate markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate static void 913*7c478bd9Sstevel@tonic-gate collecttimeout(timeout) 914*7c478bd9Sstevel@tonic-gate int timeout; 915*7c478bd9Sstevel@tonic-gate { 916*7c478bd9Sstevel@tonic-gate int save_errno = errno; 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate /* 919*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 920*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 921*7c478bd9Sstevel@tonic-gate ** DOING. 922*7c478bd9Sstevel@tonic-gate */ 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate if (CollectProgress) 925*7c478bd9Sstevel@tonic-gate { 926*7c478bd9Sstevel@tonic-gate /* reset the timeout */ 927*7c478bd9Sstevel@tonic-gate CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout, 928*7c478bd9Sstevel@tonic-gate timeout); 929*7c478bd9Sstevel@tonic-gate CollectProgress = false; 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate else 932*7c478bd9Sstevel@tonic-gate { 933*7c478bd9Sstevel@tonic-gate /* event is done */ 934*7c478bd9Sstevel@tonic-gate CollectTimeout = NULL; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate 937*7c478bd9Sstevel@tonic-gate /* if no progress was made or problem resetting event, die now */ 938*7c478bd9Sstevel@tonic-gate if (CollectTimeout == NULL) 939*7c478bd9Sstevel@tonic-gate { 940*7c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 941*7c478bd9Sstevel@tonic-gate longjmp(CtxCollectTimeout, 1); 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate errno = save_errno; 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate /* 946*7c478bd9Sstevel@tonic-gate ** DFERROR -- signal error on writing the data file. 947*7c478bd9Sstevel@tonic-gate ** 948*7c478bd9Sstevel@tonic-gate ** Called by collect(). Collect() always terminates the process 949*7c478bd9Sstevel@tonic-gate ** immediately after calling dferror(), which means that the SMTP 950*7c478bd9Sstevel@tonic-gate ** session will be terminated, which means that any error message 951*7c478bd9Sstevel@tonic-gate ** issued by dferror must be a 421 error, as per RFC 821. 952*7c478bd9Sstevel@tonic-gate ** 953*7c478bd9Sstevel@tonic-gate ** Parameters: 954*7c478bd9Sstevel@tonic-gate ** df -- the file pointer for the data file. 955*7c478bd9Sstevel@tonic-gate ** msg -- detailed message. 956*7c478bd9Sstevel@tonic-gate ** e -- the current envelope. 957*7c478bd9Sstevel@tonic-gate ** 958*7c478bd9Sstevel@tonic-gate ** Returns: 959*7c478bd9Sstevel@tonic-gate ** none. 960*7c478bd9Sstevel@tonic-gate ** 961*7c478bd9Sstevel@tonic-gate ** Side Effects: 962*7c478bd9Sstevel@tonic-gate ** Gives an error message. 963*7c478bd9Sstevel@tonic-gate ** Arranges for following output to go elsewhere. 964*7c478bd9Sstevel@tonic-gate */ 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate void 967*7c478bd9Sstevel@tonic-gate dferror(df, msg, e) 968*7c478bd9Sstevel@tonic-gate SM_FILE_T *volatile df; 969*7c478bd9Sstevel@tonic-gate char *msg; 970*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 971*7c478bd9Sstevel@tonic-gate { 972*7c478bd9Sstevel@tonic-gate char *dfname; 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate dfname = queuename(e, DATAFL_LETTER); 975*7c478bd9Sstevel@tonic-gate setstat(EX_IOERR); 976*7c478bd9Sstevel@tonic-gate if (errno == ENOSPC) 977*7c478bd9Sstevel@tonic-gate { 978*7c478bd9Sstevel@tonic-gate #if STAT64 > 0 979*7c478bd9Sstevel@tonic-gate struct stat64 st; 980*7c478bd9Sstevel@tonic-gate #else /* STAT64 > 0 */ 981*7c478bd9Sstevel@tonic-gate struct stat st; 982*7c478bd9Sstevel@tonic-gate #endif /* STAT64 > 0 */ 983*7c478bd9Sstevel@tonic-gate long avail; 984*7c478bd9Sstevel@tonic-gate long bsize; 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate if ( 989*7c478bd9Sstevel@tonic-gate #if STAT64 > 0 990*7c478bd9Sstevel@tonic-gate fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 991*7c478bd9Sstevel@tonic-gate #else /* STAT64 > 0 */ 992*7c478bd9Sstevel@tonic-gate fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 993*7c478bd9Sstevel@tonic-gate #endif /* STAT64 > 0 */ 994*7c478bd9Sstevel@tonic-gate < 0) 995*7c478bd9Sstevel@tonic-gate st.st_size = 0; 996*7c478bd9Sstevel@tonic-gate (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 997*7c478bd9Sstevel@tonic-gate SM_IO_WRONLY_B, NULL, df); 998*7c478bd9Sstevel@tonic-gate if (st.st_size <= 0) 999*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 1000*7c478bd9Sstevel@tonic-gate "\n*** Mail could not be accepted"); 1001*7c478bd9Sstevel@tonic-gate else 1002*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 1003*7c478bd9Sstevel@tonic-gate "\n*** Mail of at least %llu bytes could not be accepted\n", 1004*7c478bd9Sstevel@tonic-gate (ULONGLONG_T) st.st_size); 1005*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 1006*7c478bd9Sstevel@tonic-gate "*** at %s due to lack of disk space for temp file.\n", 1007*7c478bd9Sstevel@tonic-gate MyHostName); 1008*7c478bd9Sstevel@tonic-gate avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 1009*7c478bd9Sstevel@tonic-gate &bsize); 1010*7c478bd9Sstevel@tonic-gate if (avail > 0) 1011*7c478bd9Sstevel@tonic-gate { 1012*7c478bd9Sstevel@tonic-gate if (bsize > 1024) 1013*7c478bd9Sstevel@tonic-gate avail *= bsize / 1024; 1014*7c478bd9Sstevel@tonic-gate else if (bsize < 1024) 1015*7c478bd9Sstevel@tonic-gate avail /= 1024 / bsize; 1016*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 1017*7c478bd9Sstevel@tonic-gate "*** Currently, %ld kilobytes are available for mail temp files.\n", 1018*7c478bd9Sstevel@tonic-gate avail); 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate #if 0 1021*7c478bd9Sstevel@tonic-gate /* Wrong response code; should be 421. */ 1022*7c478bd9Sstevel@tonic-gate e->e_status = "4.3.1"; 1023*7c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, "452 Out of disk space for temp file"); 1024*7c478bd9Sstevel@tonic-gate #else /* 0 */ 1025*7c478bd9Sstevel@tonic-gate syserr("421 4.3.1 Out of disk space for temp file"); 1026*7c478bd9Sstevel@tonic-gate #endif /* 0 */ 1027*7c478bd9Sstevel@tonic-gate } 1028*7c478bd9Sstevel@tonic-gate else 1029*7c478bd9Sstevel@tonic-gate syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", 1030*7c478bd9Sstevel@tonic-gate dfname, msg, (int) geteuid(), (int) getegid()); 1031*7c478bd9Sstevel@tonic-gate if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 1032*7c478bd9Sstevel@tonic-gate SM_IO_WRONLY, NULL, df) == NULL) 1033*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 1034*7c478bd9Sstevel@tonic-gate "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 1035*7c478bd9Sstevel@tonic-gate sm_errstring(errno)); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate /* 1038*7c478bd9Sstevel@tonic-gate ** EATFROM -- chew up a UNIX style from line and process 1039*7c478bd9Sstevel@tonic-gate ** 1040*7c478bd9Sstevel@tonic-gate ** This does indeed make some assumptions about the format 1041*7c478bd9Sstevel@tonic-gate ** of UNIX messages. 1042*7c478bd9Sstevel@tonic-gate ** 1043*7c478bd9Sstevel@tonic-gate ** Parameters: 1044*7c478bd9Sstevel@tonic-gate ** fm -- the from line. 1045*7c478bd9Sstevel@tonic-gate ** e -- envelope 1046*7c478bd9Sstevel@tonic-gate ** 1047*7c478bd9Sstevel@tonic-gate ** Returns: 1048*7c478bd9Sstevel@tonic-gate ** none. 1049*7c478bd9Sstevel@tonic-gate ** 1050*7c478bd9Sstevel@tonic-gate ** Side Effects: 1051*7c478bd9Sstevel@tonic-gate ** extracts what information it can from the header, 1052*7c478bd9Sstevel@tonic-gate ** such as the date. 1053*7c478bd9Sstevel@tonic-gate */ 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate #ifndef NOTUNIX 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate static char *DowList[] = 1058*7c478bd9Sstevel@tonic-gate { 1059*7c478bd9Sstevel@tonic-gate "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 1060*7c478bd9Sstevel@tonic-gate }; 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate static char *MonthList[] = 1063*7c478bd9Sstevel@tonic-gate { 1064*7c478bd9Sstevel@tonic-gate "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1065*7c478bd9Sstevel@tonic-gate "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 1066*7c478bd9Sstevel@tonic-gate NULL 1067*7c478bd9Sstevel@tonic-gate }; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate static void 1070*7c478bd9Sstevel@tonic-gate eatfrom(fm, e) 1071*7c478bd9Sstevel@tonic-gate char *volatile fm; 1072*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 1073*7c478bd9Sstevel@tonic-gate { 1074*7c478bd9Sstevel@tonic-gate register char *p; 1075*7c478bd9Sstevel@tonic-gate register char **dt; 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate if (tTd(30, 2)) 1078*7c478bd9Sstevel@tonic-gate sm_dprintf("eatfrom(%s)\n", fm); 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate /* find the date part */ 1081*7c478bd9Sstevel@tonic-gate p = fm; 1082*7c478bd9Sstevel@tonic-gate while (*p != '\0') 1083*7c478bd9Sstevel@tonic-gate { 1084*7c478bd9Sstevel@tonic-gate /* skip a word */ 1085*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ' ') 1086*7c478bd9Sstevel@tonic-gate p++; 1087*7c478bd9Sstevel@tonic-gate while (*p == ' ') 1088*7c478bd9Sstevel@tonic-gate p++; 1089*7c478bd9Sstevel@tonic-gate if (strlen(p) < 17) 1090*7c478bd9Sstevel@tonic-gate { 1091*7c478bd9Sstevel@tonic-gate /* no room for the date */ 1092*7c478bd9Sstevel@tonic-gate return; 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isupper(*p)) || 1095*7c478bd9Sstevel@tonic-gate p[3] != ' ' || p[13] != ':' || p[16] != ':') 1096*7c478bd9Sstevel@tonic-gate continue; 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate /* we have a possible date */ 1099*7c478bd9Sstevel@tonic-gate for (dt = DowList; *dt != NULL; dt++) 1100*7c478bd9Sstevel@tonic-gate if (strncmp(*dt, p, 3) == 0) 1101*7c478bd9Sstevel@tonic-gate break; 1102*7c478bd9Sstevel@tonic-gate if (*dt == NULL) 1103*7c478bd9Sstevel@tonic-gate continue; 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate for (dt = MonthList; *dt != NULL; dt++) 1106*7c478bd9Sstevel@tonic-gate { 1107*7c478bd9Sstevel@tonic-gate if (strncmp(*dt, &p[4], 3) == 0) 1108*7c478bd9Sstevel@tonic-gate break; 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate if (*dt != NULL) 1111*7c478bd9Sstevel@tonic-gate break; 1112*7c478bd9Sstevel@tonic-gate } 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate if (*p != '\0') 1115*7c478bd9Sstevel@tonic-gate { 1116*7c478bd9Sstevel@tonic-gate char *q, buf[25]; 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate /* we have found a date */ 1119*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, p, sizeof(buf)); 1120*7c478bd9Sstevel@tonic-gate q = arpadate(buf); 1121*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 'a', q); 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate } 1124*7c478bd9Sstevel@tonic-gate #endif /* ! NOTUNIX */ 1125