finis(true, true, ExitStat);
finis(false, true, ExitStat);
static SM_FILE_T *collect_dfopen __P((ENVELOPE *));static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int));/***  COLLECT_EOH -- end-of-header processing in collect()****	Called by collect() when it encounters the blank line**	separating the header from the message body, or when it**	encounters EOF in a message that contains only a header.****	Parameters:**		e -- envelope**		numhdrs -- number of headers**		hdrslen -- length of headers****	Results:**		NULL, or handle to open data file****	Side Effects:**		end-of-header check ruleset is invoked.**		envelope state is updated.**		headers may be added and deleted.**		selects the queue.**		opens the data file.*/static SM_FILE_T *collect_eoh(e, numhdrs, hdrslen)	ENVELOPE *e;	int numhdrs;	int hdrslen;{	char hnum[16];	char hsize[16];	/* call the end-of-header check ruleset */	(void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs);	(void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen);	if (tTd(30, 10))		sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",			   hnum, hsize);	(void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT,			3, NULL, e->e_id);	/*	**  Process the header,	**  select the queue, open the data file.	*/	collect_doheader(e);	return collect_dfopen(e);}/***  COLLECT_DOHEADER -- process header in collect()****	Called by collect() after it has finished parsing the header,**	but before it selects the queue and creates the data file.**	The results of processing the header will affect queue selection.****	Parameters:**		e -- envelope****	Results:**		none.****	Side Effects:**		envelope state is updated.**		headers may be added and deleted.*/static voidcollect_doheader(e)	ENVELOPE *e;{	/*	**  Find out some information from the headers.	**	Examples are who is the from person & the date.	*/	eatheader(e, true, false);	if (GrabTo && e->e_sendqueue == NULL)		usrerr("No recipient addresses found in header");	/*	**  If we have a Return-Receipt-To:, turn it into a DSN.	*/	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)	{		ADDRESS *q;		for (q = e->e_sendqueue; q != NULL; q = q->q_next)			if (!bitset(QHASNOTIFY, q->q_flags))				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;	}	/*	**  Add an appropriate recipient line if we have none.	*/	if (hvalue("to", e->e_header) != NULL ||	    hvalue("cc", e->e_header) != NULL ||	    hvalue("apparently-to", e->e_header) != NULL)	{		/* have a valid recipient header -- delete Bcc: headers */		e->e_flags |= EF_DELETE_BCC;	}	else if (hvalue("bcc", e->e_header) == NULL)	{		/* no valid recipient headers */		register ADDRESS *q;		char *hdr = NULL;		/* create a recipient field */		switch (NoRecipientAction)		{		  case NRA_ADD_APPARENTLY_TO:			hdr = "Apparently-To";			break;		  case NRA_ADD_TO:			hdr = "To";			break;		  case NRA_ADD_BCC:			addheader("Bcc", " ", 0, e);			break;		  case NRA_ADD_TO_UNDISCLOSED:			addheader("To", "undisclosed-recipients:;", 0, e);			break;		}		if (hdr != NULL)		{			for (q = e->e_sendqueue; q != NULL; q = q->q_next)			{				if (q->q_alias != NULL)					continue;				if (tTd(30, 3))					sm_dprintf("Adding %s: %s\n",						hdr, q->q_paddr);				addheader(hdr, q->q_paddr, 0, e);			}		}	}}/***  COLLECT_DFOPEN -- open the message data file****	Called by collect() after it has finished processing the header.**	Queue selection occurs at this point, possibly based on the**	envelope's recipient list and on header information.****	Parameters:**		e -- envelope****	Results:**		NULL, or a pointer to an open data file,**		into which the message body will be written by collect().****	Side Effects:**		Calls syserr, sets EF_FATALERRS and returns NULL**		if there is insufficient disk space.**		Aborts process if data file could not be opened.**		Otherwise, the queue is selected,**		e->e_{dfino,dfdev,msgsize,flags} are updated,**		and a pointer to an open data file is returned.*/static SM_FILE_T *collect_dfopen(e)	ENVELOPE *e;{	MODE_T oldumask = 0;	int dfd;	struct stat stbuf;	SM_FILE_T *df;	char *dfname;	if (!setnewqueue(e))		return NULL;	dfname = queuename(e, DATAFL_LETTER);	if (bitset(S_IWGRP, QueueFileMode))		oldumask = umask(002);	df = bfopen(dfname, QueueFileMode, DataFileBufferSize,		    SFF_OPENASROOT);	if (bitset(S_IWGRP, QueueFileMode))		(void) umask(oldumask);	if (df == NULL)	{		syserr("@Cannot create %s", dfname);		e->e_flags |= EF_NO_BODY_RETN;		flush_errors(true);		finis(true, true, ExitStat);		/* NOTREACHED */	}	dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);	if (dfd < 0 || fstat(dfd, &stbuf) < 0)		e->e_dfino = -1;	else	{		e->e_dfdev = stbuf.st_dev;		e->e_dfino = stbuf.st_ino;	}	e->e_flags |= EF_HAS_DF;	return df;}