xref: /illumos-gate/usr/src/cmd/sendmail/src/envelope.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2003 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: envelope.c,v 8.294 2005/02/16 23:38:51 ca Exp $")
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate /*
21*7c478bd9Sstevel@tonic-gate **  CLRSESSENVELOPE -- clear session oriented data in an envelope
22*7c478bd9Sstevel@tonic-gate **
23*7c478bd9Sstevel@tonic-gate **	Parameters:
24*7c478bd9Sstevel@tonic-gate **		e -- the envelope to clear.
25*7c478bd9Sstevel@tonic-gate **
26*7c478bd9Sstevel@tonic-gate **	Returns:
27*7c478bd9Sstevel@tonic-gate **		none.
28*7c478bd9Sstevel@tonic-gate */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate void
31*7c478bd9Sstevel@tonic-gate clrsessenvelope(e)
32*7c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
33*7c478bd9Sstevel@tonic-gate {
34*7c478bd9Sstevel@tonic-gate #if SASL
35*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{auth_type}"), "");
36*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{auth_authen}"), "");
37*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{auth_author}"), "");
38*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{auth_ssf}"), "");
39*7c478bd9Sstevel@tonic-gate #endif /* SASL */
40*7c478bd9Sstevel@tonic-gate #if STARTTLS
41*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{cert_issuer}"), "");
42*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{cert_subject}"), "");
43*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{cipher_bits}"), "");
44*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{cipher}"), "");
45*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{tls_version}"), "");
46*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{verify}"), "");
47*7c478bd9Sstevel@tonic-gate # if _FFR_TLS_1
48*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{alg_bits}"), "");
49*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{cn_issuer}"), "");
50*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{cn_subject}"), "");
51*7c478bd9Sstevel@tonic-gate # endif /* _FFR_TLS_1 */
52*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
53*7c478bd9Sstevel@tonic-gate }
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate **  NEWENVELOPE -- fill in a new envelope
57*7c478bd9Sstevel@tonic-gate **
58*7c478bd9Sstevel@tonic-gate **	Supports inheritance.
59*7c478bd9Sstevel@tonic-gate **
60*7c478bd9Sstevel@tonic-gate **	Parameters:
61*7c478bd9Sstevel@tonic-gate **		e -- the new envelope to fill in.
62*7c478bd9Sstevel@tonic-gate **		parent -- the envelope to be the parent of e.
63*7c478bd9Sstevel@tonic-gate **		rpool -- either NULL, or a pointer to a resource pool
64*7c478bd9Sstevel@tonic-gate **			from which envelope memory is allocated, and
65*7c478bd9Sstevel@tonic-gate **			to which envelope resources are attached.
66*7c478bd9Sstevel@tonic-gate **
67*7c478bd9Sstevel@tonic-gate **	Returns:
68*7c478bd9Sstevel@tonic-gate **		e.
69*7c478bd9Sstevel@tonic-gate **
70*7c478bd9Sstevel@tonic-gate **	Side Effects:
71*7c478bd9Sstevel@tonic-gate **		none.
72*7c478bd9Sstevel@tonic-gate */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate ENVELOPE *
75*7c478bd9Sstevel@tonic-gate newenvelope(e, parent, rpool)
76*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
77*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *parent;
78*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
79*7c478bd9Sstevel@tonic-gate {
80*7c478bd9Sstevel@tonic-gate 	/*
81*7c478bd9Sstevel@tonic-gate 	**  This code used to read:
82*7c478bd9Sstevel@tonic-gate 	**	if (e == parent && e->e_parent != NULL)
83*7c478bd9Sstevel@tonic-gate 	**		parent = e->e_parent;
84*7c478bd9Sstevel@tonic-gate 	**  So if e == parent && e->e_parent == NULL then we would
85*7c478bd9Sstevel@tonic-gate 	**  set e->e_parent = e, which creates a loop in the e_parent chain.
86*7c478bd9Sstevel@tonic-gate 	**  This meant macvalue() could go into an infinite loop.
87*7c478bd9Sstevel@tonic-gate 	*/
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	if (e == parent)
90*7c478bd9Sstevel@tonic-gate 		parent = e->e_parent;
91*7c478bd9Sstevel@tonic-gate 	clearenvelope(e, true, rpool);
92*7c478bd9Sstevel@tonic-gate 	if (e == CurEnv)
93*7c478bd9Sstevel@tonic-gate 		memmove((char *) &e->e_from,
94*7c478bd9Sstevel@tonic-gate 			(char *) &NullAddress,
95*7c478bd9Sstevel@tonic-gate 			sizeof e->e_from);
96*7c478bd9Sstevel@tonic-gate 	else
97*7c478bd9Sstevel@tonic-gate 		memmove((char *) &e->e_from,
98*7c478bd9Sstevel@tonic-gate 			(char *) &CurEnv->e_from,
99*7c478bd9Sstevel@tonic-gate 			sizeof e->e_from);
100*7c478bd9Sstevel@tonic-gate 	e->e_parent = parent;
101*7c478bd9Sstevel@tonic-gate 	assign_queueid(e);
102*7c478bd9Sstevel@tonic-gate 	e->e_ctime = curtime();
103*7c478bd9Sstevel@tonic-gate 	if (parent != NULL)
104*7c478bd9Sstevel@tonic-gate 	{
105*7c478bd9Sstevel@tonic-gate 		e->e_msgpriority = parent->e_msgsize;
106*7c478bd9Sstevel@tonic-gate 		if (parent->e_quarmsg == NULL)
107*7c478bd9Sstevel@tonic-gate 		{
108*7c478bd9Sstevel@tonic-gate 			e->e_quarmsg = NULL;
109*7c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM,
110*7c478bd9Sstevel@tonic-gate 				  macid("{quarantine}"), "");
111*7c478bd9Sstevel@tonic-gate 		}
112*7c478bd9Sstevel@tonic-gate 		else
113*7c478bd9Sstevel@tonic-gate 		{
114*7c478bd9Sstevel@tonic-gate 			e->e_quarmsg = sm_rpool_strdup_x(rpool,
115*7c478bd9Sstevel@tonic-gate 							 parent->e_quarmsg);
116*7c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM,
117*7c478bd9Sstevel@tonic-gate 				  macid("{quarantine}"), e->e_quarmsg);
118*7c478bd9Sstevel@tonic-gate 		}
119*7c478bd9Sstevel@tonic-gate 	}
120*7c478bd9Sstevel@tonic-gate 	e->e_puthdr = putheader;
121*7c478bd9Sstevel@tonic-gate 	e->e_putbody = putbody;
122*7c478bd9Sstevel@tonic-gate 	if (CurEnv->e_xfp != NULL)
123*7c478bd9Sstevel@tonic-gate 		(void) sm_io_flush(CurEnv->e_xfp, SM_TIME_DEFAULT);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	return e;
126*7c478bd9Sstevel@tonic-gate }
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate /* values for msg_timeout, see also IS_* below for usage (bit layout) */
129*7c478bd9Sstevel@tonic-gate #define MSG_T_O		0x01	/* normal timeout */
130*7c478bd9Sstevel@tonic-gate #define MSG_T_O_NOW	0x02	/* NOW timeout */
131*7c478bd9Sstevel@tonic-gate #define MSG_NOT_BY	0x04	/* Deliver-By time exceeded, mode R */
132*7c478bd9Sstevel@tonic-gate #define MSG_WARN	0x10	/* normal queue warning */
133*7c478bd9Sstevel@tonic-gate #define MSG_WARN_BY	0x20	/* Deliver-By time exceeded, mode N */
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate #define IS_MSG_ERR(x)	(((x) & 0x0f) != 0)	/* return an error */
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /* immediate return */
138*7c478bd9Sstevel@tonic-gate #define IS_IMM_RET(x)	(((x) & (MSG_T_O_NOW|MSG_NOT_BY)) != 0)
139*7c478bd9Sstevel@tonic-gate #define IS_MSG_WARN(x)	(((x) & 0xf0) != 0)	/* return a warning */
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate /*
142*7c478bd9Sstevel@tonic-gate **  DROPENVELOPE -- deallocate an envelope.
143*7c478bd9Sstevel@tonic-gate **
144*7c478bd9Sstevel@tonic-gate **	Parameters:
145*7c478bd9Sstevel@tonic-gate **		e -- the envelope to deallocate.
146*7c478bd9Sstevel@tonic-gate **		fulldrop -- if set, do return receipts.
147*7c478bd9Sstevel@tonic-gate **		split -- if true, split by recipient if message is queued up
148*7c478bd9Sstevel@tonic-gate **
149*7c478bd9Sstevel@tonic-gate **	Returns:
150*7c478bd9Sstevel@tonic-gate **		none.
151*7c478bd9Sstevel@tonic-gate **
152*7c478bd9Sstevel@tonic-gate **	Side Effects:
153*7c478bd9Sstevel@tonic-gate **		housekeeping necessary to dispose of an envelope.
154*7c478bd9Sstevel@tonic-gate **		Unlocks this queue file.
155*7c478bd9Sstevel@tonic-gate */
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate void
158*7c478bd9Sstevel@tonic-gate dropenvelope(e, fulldrop, split)
159*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
160*7c478bd9Sstevel@tonic-gate 	bool fulldrop;
161*7c478bd9Sstevel@tonic-gate 	bool split;
162*7c478bd9Sstevel@tonic-gate {
163*7c478bd9Sstevel@tonic-gate 	bool panic = false;
164*7c478bd9Sstevel@tonic-gate 	bool queueit = false;
165*7c478bd9Sstevel@tonic-gate 	int msg_timeout = 0;
166*7c478bd9Sstevel@tonic-gate 	bool failure_return = false;
167*7c478bd9Sstevel@tonic-gate 	bool delay_return = false;
168*7c478bd9Sstevel@tonic-gate 	bool success_return = false;
169*7c478bd9Sstevel@tonic-gate 	bool pmnotify = bitset(EF_PM_NOTIFY, e->e_flags);
170*7c478bd9Sstevel@tonic-gate 	bool done = false;
171*7c478bd9Sstevel@tonic-gate 	register ADDRESS *q;
172*7c478bd9Sstevel@tonic-gate 	char *id = e->e_id;
173*7c478bd9Sstevel@tonic-gate 	time_t now;
174*7c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if (tTd(50, 1))
177*7c478bd9Sstevel@tonic-gate 	{
178*7c478bd9Sstevel@tonic-gate 		sm_dprintf("dropenvelope %p: id=", e);
179*7c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), e->e_id);
180*7c478bd9Sstevel@tonic-gate 		sm_dprintf(", flags=");
181*7c478bd9Sstevel@tonic-gate 		printenvflags(e);
182*7c478bd9Sstevel@tonic-gate 		if (tTd(50, 10))
183*7c478bd9Sstevel@tonic-gate 		{
184*7c478bd9Sstevel@tonic-gate 			sm_dprintf("sendq=");
185*7c478bd9Sstevel@tonic-gate 			printaddr(sm_debug_file(), e->e_sendqueue, true);
186*7c478bd9Sstevel@tonic-gate 		}
187*7c478bd9Sstevel@tonic-gate 	}
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if (LogLevel > 84)
190*7c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_DEBUG, id,
191*7c478bd9Sstevel@tonic-gate 			  "dropenvelope, e_flags=0x%lx, OpMode=%c, pid=%d",
192*7c478bd9Sstevel@tonic-gate 			  e->e_flags, OpMode, (int) CurrentPid);
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/* we must have an id to remove disk files */
195*7c478bd9Sstevel@tonic-gate 	if (id == NULL)
196*7c478bd9Sstevel@tonic-gate 		return;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	/* if verify-only mode, we can skip most of this */
199*7c478bd9Sstevel@tonic-gate 	if (OpMode == MD_VERIFY)
200*7c478bd9Sstevel@tonic-gate 		goto simpledrop;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
203*7c478bd9Sstevel@tonic-gate 		logsender(e, NULL);
204*7c478bd9Sstevel@tonic-gate 	e->e_flags &= ~EF_LOGSENDER;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	/* post statistics */
207*7c478bd9Sstevel@tonic-gate 	poststats(StatFile);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	/*
210*7c478bd9Sstevel@tonic-gate 	**  Extract state information from dregs of send list.
211*7c478bd9Sstevel@tonic-gate 	*/
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	now = curtime();
214*7c478bd9Sstevel@tonic-gate 	if (now >= e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
215*7c478bd9Sstevel@tonic-gate 		msg_timeout = MSG_T_O;
216*7c478bd9Sstevel@tonic-gate 	if (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
217*7c478bd9Sstevel@tonic-gate 	    now >= e->e_ctime + e->e_deliver_by &&
218*7c478bd9Sstevel@tonic-gate 	    !bitset(EF_RESPONSE, e->e_flags))
219*7c478bd9Sstevel@tonic-gate 	{
220*7c478bd9Sstevel@tonic-gate 		msg_timeout = MSG_NOT_BY;
221*7c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
222*7c478bd9Sstevel@tonic-gate 	}
223*7c478bd9Sstevel@tonic-gate 	else if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
224*7c478bd9Sstevel@tonic-gate 		 !bitset(EF_RESPONSE, e->e_flags))
225*7c478bd9Sstevel@tonic-gate 	{
226*7c478bd9Sstevel@tonic-gate 		msg_timeout = MSG_T_O_NOW;
227*7c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	e->e_flags &= ~EF_QUEUERUN;
231*7c478bd9Sstevel@tonic-gate 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
232*7c478bd9Sstevel@tonic-gate 	{
233*7c478bd9Sstevel@tonic-gate 		if (QS_IS_UNDELIVERED(q->q_state))
234*7c478bd9Sstevel@tonic-gate 			queueit = true;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 		/* see if a notification is needed */
237*7c478bd9Sstevel@tonic-gate 		if (bitset(QPINGONFAILURE, q->q_flags) &&
238*7c478bd9Sstevel@tonic-gate 		    ((IS_MSG_ERR(msg_timeout) &&
239*7c478bd9Sstevel@tonic-gate 		      QS_IS_UNDELIVERED(q->q_state)) ||
240*7c478bd9Sstevel@tonic-gate 		     QS_IS_BADADDR(q->q_state) ||
241*7c478bd9Sstevel@tonic-gate 		     IS_IMM_RET(msg_timeout)))
242*7c478bd9Sstevel@tonic-gate 		{
243*7c478bd9Sstevel@tonic-gate 			failure_return = true;
244*7c478bd9Sstevel@tonic-gate 			if (!done && q->q_owner == NULL &&
245*7c478bd9Sstevel@tonic-gate 			    !emptyaddr(&e->e_from))
246*7c478bd9Sstevel@tonic-gate 			{
247*7c478bd9Sstevel@tonic-gate 				(void) sendtolist(e->e_from.q_paddr, NULLADDR,
248*7c478bd9Sstevel@tonic-gate 						  &e->e_errorqueue, 0, e);
249*7c478bd9Sstevel@tonic-gate 				done = true;
250*7c478bd9Sstevel@tonic-gate 			}
251*7c478bd9Sstevel@tonic-gate 		}
252*7c478bd9Sstevel@tonic-gate 		else if ((bitset(QPINGONSUCCESS, q->q_flags) &&
253*7c478bd9Sstevel@tonic-gate 			  ((QS_IS_SENT(q->q_state) &&
254*7c478bd9Sstevel@tonic-gate 			    bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
255*7c478bd9Sstevel@tonic-gate 			   bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags))) ||
256*7c478bd9Sstevel@tonic-gate 			  bitset(QBYTRACE, q->q_flags) ||
257*7c478bd9Sstevel@tonic-gate 			  bitset(QBYNRELAY, q->q_flags))
258*7c478bd9Sstevel@tonic-gate 		{
259*7c478bd9Sstevel@tonic-gate 			success_return = true;
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (e->e_class < 0)
264*7c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_NO_BODY_RETN;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	/*
267*7c478bd9Sstevel@tonic-gate 	**  See if the message timed out.
268*7c478bd9Sstevel@tonic-gate 	*/
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	if (!queueit)
271*7c478bd9Sstevel@tonic-gate 		/* EMPTY */
272*7c478bd9Sstevel@tonic-gate 		/* nothing to do */ ;
273*7c478bd9Sstevel@tonic-gate 	else if (IS_MSG_ERR(msg_timeout))
274*7c478bd9Sstevel@tonic-gate 	{
275*7c478bd9Sstevel@tonic-gate 		if (failure_return)
276*7c478bd9Sstevel@tonic-gate 		{
277*7c478bd9Sstevel@tonic-gate 			if (msg_timeout == MSG_NOT_BY)
278*7c478bd9Sstevel@tonic-gate 			{
279*7c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(buf, sizeof buf,
280*7c478bd9Sstevel@tonic-gate 					"delivery time expired %lds",
281*7c478bd9Sstevel@tonic-gate 					e->e_deliver_by);
282*7c478bd9Sstevel@tonic-gate 			}
283*7c478bd9Sstevel@tonic-gate 			else
284*7c478bd9Sstevel@tonic-gate 			{
285*7c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(buf, sizeof buf,
286*7c478bd9Sstevel@tonic-gate 					"Cannot send message for %s",
287*7c478bd9Sstevel@tonic-gate 					pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
288*7c478bd9Sstevel@tonic-gate 						false));
289*7c478bd9Sstevel@tonic-gate 			}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 			/* don't free, allocated from e_rpool */
292*7c478bd9Sstevel@tonic-gate 			e->e_message = sm_rpool_strdup_x(e->e_rpool, buf);
293*7c478bd9Sstevel@tonic-gate 			message(buf);
294*7c478bd9Sstevel@tonic-gate 			e->e_flags |= EF_CLRQUEUE;
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 		if (msg_timeout == MSG_NOT_BY)
297*7c478bd9Sstevel@tonic-gate 		{
298*7c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
299*7c478bd9Sstevel@tonic-gate 				"Delivery time (%lds) expired\n",
300*7c478bd9Sstevel@tonic-gate 				e->e_deliver_by);
301*7c478bd9Sstevel@tonic-gate 		}
302*7c478bd9Sstevel@tonic-gate 		else
303*7c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
304*7c478bd9Sstevel@tonic-gate 				"Message could not be delivered for %s\n",
305*7c478bd9Sstevel@tonic-gate 				pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
306*7c478bd9Sstevel@tonic-gate 					false));
307*7c478bd9Sstevel@tonic-gate 		(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
308*7c478bd9Sstevel@tonic-gate 			"Message will be deleted from queue\n");
309*7c478bd9Sstevel@tonic-gate 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
310*7c478bd9Sstevel@tonic-gate 		{
311*7c478bd9Sstevel@tonic-gate 			if (QS_IS_UNDELIVERED(q->q_state))
312*7c478bd9Sstevel@tonic-gate 			{
313*7c478bd9Sstevel@tonic-gate 				q->q_state = QS_BADADDR;
314*7c478bd9Sstevel@tonic-gate 				if (msg_timeout == MSG_NOT_BY)
315*7c478bd9Sstevel@tonic-gate 					q->q_status = "5.4.7";
316*7c478bd9Sstevel@tonic-gate 				else
317*7c478bd9Sstevel@tonic-gate 					q->q_status = "4.4.7";
318*7c478bd9Sstevel@tonic-gate 			}
319*7c478bd9Sstevel@tonic-gate 		}
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 	else
322*7c478bd9Sstevel@tonic-gate 	{
323*7c478bd9Sstevel@tonic-gate 		if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
324*7c478bd9Sstevel@tonic-gate 		    now >= e->e_ctime +
325*7c478bd9Sstevel@tonic-gate 				TimeOuts.to_q_warning[e->e_timeoutclass])
326*7c478bd9Sstevel@tonic-gate 			msg_timeout = MSG_WARN;
327*7c478bd9Sstevel@tonic-gate 		else if (IS_DLVR_NOTIFY(e) &&
328*7c478bd9Sstevel@tonic-gate 			 e->e_deliver_by > 0 &&
329*7c478bd9Sstevel@tonic-gate 			 now >= e->e_ctime + e->e_deliver_by)
330*7c478bd9Sstevel@tonic-gate 			msg_timeout = MSG_WARN_BY;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 		if (IS_MSG_WARN(msg_timeout))
333*7c478bd9Sstevel@tonic-gate 		{
334*7c478bd9Sstevel@tonic-gate 			if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
335*7c478bd9Sstevel@tonic-gate 			    e->e_class >= 0 &&
336*7c478bd9Sstevel@tonic-gate 			    e->e_from.q_paddr != NULL &&
337*7c478bd9Sstevel@tonic-gate 			    strcmp(e->e_from.q_paddr, "<>") != 0 &&
338*7c478bd9Sstevel@tonic-gate 			    sm_strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
339*7c478bd9Sstevel@tonic-gate 			    (strlen(e->e_from.q_paddr) <= 8 ||
340*7c478bd9Sstevel@tonic-gate 			     sm_strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8],
341*7c478bd9Sstevel@tonic-gate 					   "-request") != 0))
342*7c478bd9Sstevel@tonic-gate 			{
343*7c478bd9Sstevel@tonic-gate 				for (q = e->e_sendqueue; q != NULL;
344*7c478bd9Sstevel@tonic-gate 				     q = q->q_next)
345*7c478bd9Sstevel@tonic-gate 				{
346*7c478bd9Sstevel@tonic-gate 					if (QS_IS_UNDELIVERED(q->q_state)
347*7c478bd9Sstevel@tonic-gate #if _FFR_NODELAYDSN_ON_HOLD
348*7c478bd9Sstevel@tonic-gate 					    && !bitnset(M_HOLD,
349*7c478bd9Sstevel@tonic-gate 							q->q_mailer->m_flags)
350*7c478bd9Sstevel@tonic-gate #endif /* _FFR_NODELAYDSN_ON_HOLD */
351*7c478bd9Sstevel@tonic-gate 					   )
352*7c478bd9Sstevel@tonic-gate 					{
353*7c478bd9Sstevel@tonic-gate 						if (msg_timeout ==
354*7c478bd9Sstevel@tonic-gate 						    MSG_WARN_BY &&
355*7c478bd9Sstevel@tonic-gate 						    (bitset(QPINGONDELAY,
356*7c478bd9Sstevel@tonic-gate 							    q->q_flags) ||
357*7c478bd9Sstevel@tonic-gate 						    !bitset(QHASNOTIFY,
358*7c478bd9Sstevel@tonic-gate 							    q->q_flags))
359*7c478bd9Sstevel@tonic-gate 						   )
360*7c478bd9Sstevel@tonic-gate 						{
361*7c478bd9Sstevel@tonic-gate 							q->q_flags |= QBYNDELAY;
362*7c478bd9Sstevel@tonic-gate 							delay_return = true;
363*7c478bd9Sstevel@tonic-gate 						}
364*7c478bd9Sstevel@tonic-gate 						if (bitset(QPINGONDELAY,
365*7c478bd9Sstevel@tonic-gate 							   q->q_flags))
366*7c478bd9Sstevel@tonic-gate 						{
367*7c478bd9Sstevel@tonic-gate 							q->q_flags |= QDELAYED;
368*7c478bd9Sstevel@tonic-gate 							delay_return = true;
369*7c478bd9Sstevel@tonic-gate 						}
370*7c478bd9Sstevel@tonic-gate 					}
371*7c478bd9Sstevel@tonic-gate 				}
372*7c478bd9Sstevel@tonic-gate 			}
373*7c478bd9Sstevel@tonic-gate 			if (delay_return)
374*7c478bd9Sstevel@tonic-gate 			{
375*7c478bd9Sstevel@tonic-gate 				if (msg_timeout == MSG_WARN_BY)
376*7c478bd9Sstevel@tonic-gate 				{
377*7c478bd9Sstevel@tonic-gate 					(void) sm_snprintf(buf, sizeof buf,
378*7c478bd9Sstevel@tonic-gate 						"Warning: Delivery time (%lds) exceeded",
379*7c478bd9Sstevel@tonic-gate 						e->e_deliver_by);
380*7c478bd9Sstevel@tonic-gate 				}
381*7c478bd9Sstevel@tonic-gate 				else
382*7c478bd9Sstevel@tonic-gate 					(void) sm_snprintf(buf, sizeof buf,
383*7c478bd9Sstevel@tonic-gate 						"Warning: could not send message for past %s",
384*7c478bd9Sstevel@tonic-gate 						pintvl(TimeOuts.to_q_warning[e->e_timeoutclass],
385*7c478bd9Sstevel@tonic-gate 							false));
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 				/* don't free, allocated from e_rpool */
388*7c478bd9Sstevel@tonic-gate 				e->e_message = sm_rpool_strdup_x(e->e_rpool,
389*7c478bd9Sstevel@tonic-gate 								 buf);
390*7c478bd9Sstevel@tonic-gate 				message(buf);
391*7c478bd9Sstevel@tonic-gate 				e->e_flags |= EF_WARNING;
392*7c478bd9Sstevel@tonic-gate 			}
393*7c478bd9Sstevel@tonic-gate 			if (msg_timeout == MSG_WARN_BY)
394*7c478bd9Sstevel@tonic-gate 			{
395*7c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
396*7c478bd9Sstevel@tonic-gate 					"Warning: Delivery time (%lds) exceeded\n",
397*7c478bd9Sstevel@tonic-gate 					e->e_deliver_by);
398*7c478bd9Sstevel@tonic-gate 			}
399*7c478bd9Sstevel@tonic-gate 			else
400*7c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
401*7c478bd9Sstevel@tonic-gate 					"Warning: message still undelivered after %s\n",
402*7c478bd9Sstevel@tonic-gate 					pintvl(TimeOuts.to_q_warning[e->e_timeoutclass],
403*7c478bd9Sstevel@tonic-gate 					     false));
404*7c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
405*7c478bd9Sstevel@tonic-gate 				      "Will keep trying until message is %s old\n",
406*7c478bd9Sstevel@tonic-gate 				      pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
407*7c478bd9Sstevel@tonic-gate 					     false));
408*7c478bd9Sstevel@tonic-gate 		}
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	if (tTd(50, 2))
412*7c478bd9Sstevel@tonic-gate 		sm_dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
413*7c478bd9Sstevel@tonic-gate 			failure_return, delay_return, success_return, queueit);
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	/*
416*7c478bd9Sstevel@tonic-gate 	**  If we had some fatal error, but no addresses are marked as
417*7c478bd9Sstevel@tonic-gate 	**  bad, mark them _all_ as bad.
418*7c478bd9Sstevel@tonic-gate 	*/
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
421*7c478bd9Sstevel@tonic-gate 	{
422*7c478bd9Sstevel@tonic-gate 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
423*7c478bd9Sstevel@tonic-gate 		{
424*7c478bd9Sstevel@tonic-gate 			if ((QS_IS_OK(q->q_state) ||
425*7c478bd9Sstevel@tonic-gate 			     QS_IS_VERIFIED(q->q_state)) &&
426*7c478bd9Sstevel@tonic-gate 			    bitset(QPINGONFAILURE, q->q_flags))
427*7c478bd9Sstevel@tonic-gate 			{
428*7c478bd9Sstevel@tonic-gate 				failure_return = true;
429*7c478bd9Sstevel@tonic-gate 				q->q_state = QS_BADADDR;
430*7c478bd9Sstevel@tonic-gate 			}
431*7c478bd9Sstevel@tonic-gate 		}
432*7c478bd9Sstevel@tonic-gate 	}
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	/*
435*7c478bd9Sstevel@tonic-gate 	**  Send back return receipts as requested.
436*7c478bd9Sstevel@tonic-gate 	*/
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	if (success_return && !failure_return && !delay_return && fulldrop &&
439*7c478bd9Sstevel@tonic-gate 	    !bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
440*7c478bd9Sstevel@tonic-gate 	    strcmp(e->e_from.q_paddr, "<>") != 0)
441*7c478bd9Sstevel@tonic-gate 	{
442*7c478bd9Sstevel@tonic-gate 		auto ADDRESS *rlist = NULL;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		if (tTd(50, 8))
445*7c478bd9Sstevel@tonic-gate 			sm_dprintf("dropenvelope(%s): sending return receipt\n",
446*7c478bd9Sstevel@tonic-gate 				id);
447*7c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_SENDRECEIPT;
448*7c478bd9Sstevel@tonic-gate 		(void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
449*7c478bd9Sstevel@tonic-gate 		(void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e);
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate 	e->e_flags &= ~EF_SENDRECEIPT;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	/*
454*7c478bd9Sstevel@tonic-gate 	**  Arrange to send error messages if there are fatal errors.
455*7c478bd9Sstevel@tonic-gate 	*/
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
458*7c478bd9Sstevel@tonic-gate 	{
459*7c478bd9Sstevel@tonic-gate 		if (tTd(50, 8))
460*7c478bd9Sstevel@tonic-gate 			sm_dprintf("dropenvelope(%s): saving mail\n", id);
461*7c478bd9Sstevel@tonic-gate 		panic = savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	/*
465*7c478bd9Sstevel@tonic-gate 	**  Arrange to send warning messages to postmaster as requested.
466*7c478bd9Sstevel@tonic-gate 	*/
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	if ((failure_return || pmnotify) &&
469*7c478bd9Sstevel@tonic-gate 	    PostMasterCopy != NULL &&
470*7c478bd9Sstevel@tonic-gate 	    !bitset(EF_RESPONSE, e->e_flags) &&
471*7c478bd9Sstevel@tonic-gate 	    e->e_class >= 0)
472*7c478bd9Sstevel@tonic-gate 	{
473*7c478bd9Sstevel@tonic-gate 		auto ADDRESS *rlist = NULL;
474*7c478bd9Sstevel@tonic-gate 		char pcopy[MAXNAME];
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 		if (failure_return)
477*7c478bd9Sstevel@tonic-gate 		{
478*7c478bd9Sstevel@tonic-gate 			expand(PostMasterCopy, pcopy, sizeof pcopy, e);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 			if (tTd(50, 8))
481*7c478bd9Sstevel@tonic-gate 				sm_dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
482*7c478bd9Sstevel@tonic-gate 					id, pcopy);
483*7c478bd9Sstevel@tonic-gate 			(void) sendtolist(pcopy, NULLADDR, &rlist, 0, e);
484*7c478bd9Sstevel@tonic-gate 		}
485*7c478bd9Sstevel@tonic-gate 		if (pmnotify)
486*7c478bd9Sstevel@tonic-gate 			(void) sendtolist("postmaster", NULLADDR,
487*7c478bd9Sstevel@tonic-gate 					  &rlist, 0, e);
488*7c478bd9Sstevel@tonic-gate 		(void) returntosender(e->e_message, rlist,
489*7c478bd9Sstevel@tonic-gate 				      RTSF_PM_BOUNCE|RTSF_NO_BODY, e);
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	/*
493*7c478bd9Sstevel@tonic-gate 	**  Instantiate or deinstantiate the queue.
494*7c478bd9Sstevel@tonic-gate 	*/
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate simpledrop:
497*7c478bd9Sstevel@tonic-gate 	if (tTd(50, 8))
498*7c478bd9Sstevel@tonic-gate 		sm_dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
499*7c478bd9Sstevel@tonic-gate 			id, queueit);
500*7c478bd9Sstevel@tonic-gate 	if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
501*7c478bd9Sstevel@tonic-gate 	{
502*7c478bd9Sstevel@tonic-gate 		if (tTd(50, 1))
503*7c478bd9Sstevel@tonic-gate 		{
504*7c478bd9Sstevel@tonic-gate 			sm_dprintf("\n===== Dropping queue files for %s... queueit=%d, e_flags=",
505*7c478bd9Sstevel@tonic-gate 				e->e_id, queueit);
506*7c478bd9Sstevel@tonic-gate 			printenvflags(e);
507*7c478bd9Sstevel@tonic-gate 		}
508*7c478bd9Sstevel@tonic-gate 		if (!panic)
509*7c478bd9Sstevel@tonic-gate 			(void) xunlink(queuename(e, DATAFL_LETTER));
510*7c478bd9Sstevel@tonic-gate 		if (panic && QueueMode == QM_LOST)
511*7c478bd9Sstevel@tonic-gate 		{
512*7c478bd9Sstevel@tonic-gate 			/*
513*7c478bd9Sstevel@tonic-gate 			**  leave the Qf file behind as
514*7c478bd9Sstevel@tonic-gate 			**  the delivery attempt failed.
515*7c478bd9Sstevel@tonic-gate 			*/
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 			/* EMPTY */
518*7c478bd9Sstevel@tonic-gate 		}
519*7c478bd9Sstevel@tonic-gate 		else
520*7c478bd9Sstevel@tonic-gate 		if (xunlink(queuename(e, ANYQFL_LETTER)) == 0)
521*7c478bd9Sstevel@tonic-gate 		{
522*7c478bd9Sstevel@tonic-gate 			/* add to available space in filesystem */
523*7c478bd9Sstevel@tonic-gate 			updfs(e, -1, panic ? 0 : -1, "dropenvelope");
524*7c478bd9Sstevel@tonic-gate 		}
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		if (e->e_ntries > 0 && LogLevel > 9)
527*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, id, "done; delay=%s, ntries=%d",
528*7c478bd9Sstevel@tonic-gate 				  pintvl(curtime() - e->e_ctime, true),
529*7c478bd9Sstevel@tonic-gate 				  e->e_ntries);
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
532*7c478bd9Sstevel@tonic-gate 	{
533*7c478bd9Sstevel@tonic-gate 		if (!split)
534*7c478bd9Sstevel@tonic-gate 			queueup(e, false, true);
535*7c478bd9Sstevel@tonic-gate 		else
536*7c478bd9Sstevel@tonic-gate 		{
537*7c478bd9Sstevel@tonic-gate 			ENVELOPE *oldsib;
538*7c478bd9Sstevel@tonic-gate 			ENVELOPE *ee;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 			/*
541*7c478bd9Sstevel@tonic-gate 			**  Save old sibling and set it to NULL to avoid
542*7c478bd9Sstevel@tonic-gate 			**  queueing up the same envelopes again.
543*7c478bd9Sstevel@tonic-gate 			**  This requires that envelopes in that list have
544*7c478bd9Sstevel@tonic-gate 			**  been take care of before (or at some other place).
545*7c478bd9Sstevel@tonic-gate 			*/
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 			oldsib = e->e_sibling;
548*7c478bd9Sstevel@tonic-gate 			e->e_sibling = NULL;
549*7c478bd9Sstevel@tonic-gate 			if (!split_by_recipient(e) &&
550*7c478bd9Sstevel@tonic-gate 			    bitset(EF_FATALERRS, e->e_flags))
551*7c478bd9Sstevel@tonic-gate 			{
552*7c478bd9Sstevel@tonic-gate 				syserr("!dropenvelope(%s): cannot commit data file %s, uid=%d",
553*7c478bd9Sstevel@tonic-gate 					e->e_id, queuename(e, DATAFL_LETTER),
554*7c478bd9Sstevel@tonic-gate 					(int) geteuid());
555*7c478bd9Sstevel@tonic-gate 			}
556*7c478bd9Sstevel@tonic-gate 			for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
557*7c478bd9Sstevel@tonic-gate 				queueup(ee, false, true);
558*7c478bd9Sstevel@tonic-gate 			queueup(e, false, true);
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 			/* clean up */
561*7c478bd9Sstevel@tonic-gate 			for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
562*7c478bd9Sstevel@tonic-gate 			{
563*7c478bd9Sstevel@tonic-gate 				/* now unlock the job */
564*7c478bd9Sstevel@tonic-gate 				if (tTd(50, 8))
565*7c478bd9Sstevel@tonic-gate 					sm_dprintf("dropenvelope(%s): unlocking job\n",
566*7c478bd9Sstevel@tonic-gate 						   ee->e_id);
567*7c478bd9Sstevel@tonic-gate 				closexscript(ee);
568*7c478bd9Sstevel@tonic-gate 				unlockqueue(ee);
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 				/* this envelope is marked unused */
571*7c478bd9Sstevel@tonic-gate 				if (ee->e_dfp != NULL)
572*7c478bd9Sstevel@tonic-gate 				{
573*7c478bd9Sstevel@tonic-gate 					(void) sm_io_close(ee->e_dfp,
574*7c478bd9Sstevel@tonic-gate 							   SM_TIME_DEFAULT);
575*7c478bd9Sstevel@tonic-gate 					ee->e_dfp = NULL;
576*7c478bd9Sstevel@tonic-gate 				}
577*7c478bd9Sstevel@tonic-gate 				ee->e_id = NULL;
578*7c478bd9Sstevel@tonic-gate 				ee->e_flags &= ~EF_HAS_DF;
579*7c478bd9Sstevel@tonic-gate 			}
580*7c478bd9Sstevel@tonic-gate 			e->e_sibling = oldsib;
581*7c478bd9Sstevel@tonic-gate 		}
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	/* now unlock the job */
585*7c478bd9Sstevel@tonic-gate 	if (tTd(50, 8))
586*7c478bd9Sstevel@tonic-gate 		sm_dprintf("dropenvelope(%s): unlocking job\n", id);
587*7c478bd9Sstevel@tonic-gate 	closexscript(e);
588*7c478bd9Sstevel@tonic-gate 	unlockqueue(e);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	/* make sure that this envelope is marked unused */
591*7c478bd9Sstevel@tonic-gate 	if (e->e_dfp != NULL)
592*7c478bd9Sstevel@tonic-gate 	{
593*7c478bd9Sstevel@tonic-gate 		(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
594*7c478bd9Sstevel@tonic-gate 		e->e_dfp = NULL;
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 	e->e_id = NULL;
597*7c478bd9Sstevel@tonic-gate 	e->e_flags &= ~EF_HAS_DF;
598*7c478bd9Sstevel@tonic-gate }
599*7c478bd9Sstevel@tonic-gate /*
600*7c478bd9Sstevel@tonic-gate **  CLEARENVELOPE -- clear an envelope without unlocking
601*7c478bd9Sstevel@tonic-gate **
602*7c478bd9Sstevel@tonic-gate **	This is normally used by a child process to get a clean
603*7c478bd9Sstevel@tonic-gate **	envelope without disturbing the parent.
604*7c478bd9Sstevel@tonic-gate **
605*7c478bd9Sstevel@tonic-gate **	Parameters:
606*7c478bd9Sstevel@tonic-gate **		e -- the envelope to clear.
607*7c478bd9Sstevel@tonic-gate **		fullclear - if set, the current envelope is total
608*7c478bd9Sstevel@tonic-gate **			garbage and should be ignored; otherwise,
609*7c478bd9Sstevel@tonic-gate **			release any resources it may indicate.
610*7c478bd9Sstevel@tonic-gate **		rpool -- either NULL, or a pointer to a resource pool
611*7c478bd9Sstevel@tonic-gate **			from which envelope memory is allocated, and
612*7c478bd9Sstevel@tonic-gate **			to which envelope resources are attached.
613*7c478bd9Sstevel@tonic-gate **
614*7c478bd9Sstevel@tonic-gate **	Returns:
615*7c478bd9Sstevel@tonic-gate **		none.
616*7c478bd9Sstevel@tonic-gate **
617*7c478bd9Sstevel@tonic-gate **	Side Effects:
618*7c478bd9Sstevel@tonic-gate **		Closes files associated with the envelope.
619*7c478bd9Sstevel@tonic-gate **		Marks the envelope as unallocated.
620*7c478bd9Sstevel@tonic-gate */
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate void
623*7c478bd9Sstevel@tonic-gate clearenvelope(e, fullclear, rpool)
624*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
625*7c478bd9Sstevel@tonic-gate 	bool fullclear;
626*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
627*7c478bd9Sstevel@tonic-gate {
628*7c478bd9Sstevel@tonic-gate 	register HDR *bh;
629*7c478bd9Sstevel@tonic-gate 	register HDR **nhp;
630*7c478bd9Sstevel@tonic-gate 	extern ENVELOPE BlankEnvelope;
631*7c478bd9Sstevel@tonic-gate 	char **p;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if (!fullclear)
634*7c478bd9Sstevel@tonic-gate 	{
635*7c478bd9Sstevel@tonic-gate 		/* clear out any file information */
636*7c478bd9Sstevel@tonic-gate 		if (e->e_xfp != NULL)
637*7c478bd9Sstevel@tonic-gate 			(void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
638*7c478bd9Sstevel@tonic-gate 		if (e->e_dfp != NULL)
639*7c478bd9Sstevel@tonic-gate 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
640*7c478bd9Sstevel@tonic-gate 		e->e_xfp = e->e_dfp = NULL;
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	/*
644*7c478bd9Sstevel@tonic-gate 	**  Copy BlankEnvelope into *e.
645*7c478bd9Sstevel@tonic-gate 	**  It is not safe to simply copy pointers to strings;
646*7c478bd9Sstevel@tonic-gate 	**  the strings themselves must be copied (or set to NULL).
647*7c478bd9Sstevel@tonic-gate 	**  The problem is that when we assign a new string value to
648*7c478bd9Sstevel@tonic-gate 	**  a member of BlankEnvelope, we free the old string.
649*7c478bd9Sstevel@tonic-gate 	**  We did not need to do this copying in sendmail 8.11 :-(
650*7c478bd9Sstevel@tonic-gate 	**  and it is a potential performance hit.  Reference counted
651*7c478bd9Sstevel@tonic-gate 	**  strings are one way out.
652*7c478bd9Sstevel@tonic-gate 	*/
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	*e = BlankEnvelope;
655*7c478bd9Sstevel@tonic-gate 	e->e_message = NULL;
656*7c478bd9Sstevel@tonic-gate 	e->e_qfletter = '\0';
657*7c478bd9Sstevel@tonic-gate 	e->e_quarmsg = NULL;
658*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), "");
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/*
661*7c478bd9Sstevel@tonic-gate 	**  Copy the macro table.
662*7c478bd9Sstevel@tonic-gate 	**  We might be able to avoid this by zeroing the macro table
663*7c478bd9Sstevel@tonic-gate 	**  and always searching BlankEnvelope.e_macro after e->e_macro
664*7c478bd9Sstevel@tonic-gate 	**  in macvalue().
665*7c478bd9Sstevel@tonic-gate 	*/
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	for (p = &e->e_macro.mac_table[0];
668*7c478bd9Sstevel@tonic-gate 	     p <= &e->e_macro.mac_table[MAXMACROID];
669*7c478bd9Sstevel@tonic-gate 	     ++p)
670*7c478bd9Sstevel@tonic-gate 	{
671*7c478bd9Sstevel@tonic-gate 		if (*p != NULL)
672*7c478bd9Sstevel@tonic-gate 			*p = sm_rpool_strdup_x(rpool, *p);
673*7c478bd9Sstevel@tonic-gate 	}
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 	/*
676*7c478bd9Sstevel@tonic-gate 	**  XXX There are many strings in the envelope structure
677*7c478bd9Sstevel@tonic-gate 	**  XXX that we are not attempting to copy here.
678*7c478bd9Sstevel@tonic-gate 	**  XXX Investigate this further.
679*7c478bd9Sstevel@tonic-gate 	*/
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	e->e_rpool = rpool;
682*7c478bd9Sstevel@tonic-gate 	e->e_macro.mac_rpool = rpool;
683*7c478bd9Sstevel@tonic-gate 	if (Verbose)
684*7c478bd9Sstevel@tonic-gate 		set_delivery_mode(SM_DELIVER, e);
685*7c478bd9Sstevel@tonic-gate 	bh = BlankEnvelope.e_header;
686*7c478bd9Sstevel@tonic-gate 	nhp = &e->e_header;
687*7c478bd9Sstevel@tonic-gate 	while (bh != NULL)
688*7c478bd9Sstevel@tonic-gate 	{
689*7c478bd9Sstevel@tonic-gate 		*nhp = (HDR *) sm_rpool_malloc_x(rpool, sizeof *bh);
690*7c478bd9Sstevel@tonic-gate 		memmove((char *) *nhp, (char *) bh, sizeof *bh);
691*7c478bd9Sstevel@tonic-gate 		bh = bh->h_link;
692*7c478bd9Sstevel@tonic-gate 		nhp = &(*nhp)->h_link;
693*7c478bd9Sstevel@tonic-gate 	}
694*7c478bd9Sstevel@tonic-gate }
695*7c478bd9Sstevel@tonic-gate /*
696*7c478bd9Sstevel@tonic-gate **  INITSYS -- initialize instantiation of system
697*7c478bd9Sstevel@tonic-gate **
698*7c478bd9Sstevel@tonic-gate **	In Daemon mode, this is done in the child.
699*7c478bd9Sstevel@tonic-gate **
700*7c478bd9Sstevel@tonic-gate **	Parameters:
701*7c478bd9Sstevel@tonic-gate **		e -- the envelope to use.
702*7c478bd9Sstevel@tonic-gate **
703*7c478bd9Sstevel@tonic-gate **	Returns:
704*7c478bd9Sstevel@tonic-gate **		none.
705*7c478bd9Sstevel@tonic-gate **
706*7c478bd9Sstevel@tonic-gate **	Side Effects:
707*7c478bd9Sstevel@tonic-gate **		Initializes the system macros, some global variables,
708*7c478bd9Sstevel@tonic-gate **		etc.  In particular, the current time in various
709*7c478bd9Sstevel@tonic-gate **		forms is set.
710*7c478bd9Sstevel@tonic-gate */
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate void
713*7c478bd9Sstevel@tonic-gate initsys(e)
714*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
715*7c478bd9Sstevel@tonic-gate {
716*7c478bd9Sstevel@tonic-gate 	char buf[10];
717*7c478bd9Sstevel@tonic-gate #ifdef TTYNAME
718*7c478bd9Sstevel@tonic-gate 	static char ybuf[60];			/* holds tty id */
719*7c478bd9Sstevel@tonic-gate 	register char *p;
720*7c478bd9Sstevel@tonic-gate 	extern char *ttyname();
721*7c478bd9Sstevel@tonic-gate #endif /* TTYNAME */
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	/*
724*7c478bd9Sstevel@tonic-gate 	**  Give this envelope a reality.
725*7c478bd9Sstevel@tonic-gate 	**	I.e., an id, a transcript, and a creation time.
726*7c478bd9Sstevel@tonic-gate 	**  We don't select the queue until all of the recipients are known.
727*7c478bd9Sstevel@tonic-gate 	*/
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	openxscript(e);
730*7c478bd9Sstevel@tonic-gate 	e->e_ctime = curtime();
731*7c478bd9Sstevel@tonic-gate 	e->e_qfletter = '\0';
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	/*
734*7c478bd9Sstevel@tonic-gate 	**  Set OutChannel to something useful if stdout isn't it.
735*7c478bd9Sstevel@tonic-gate 	**	This arranges that any extra stuff the mailer produces
736*7c478bd9Sstevel@tonic-gate 	**	gets sent back to the user on error (because it is
737*7c478bd9Sstevel@tonic-gate 	**	tucked away in the transcript).
738*7c478bd9Sstevel@tonic-gate 	*/
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
741*7c478bd9Sstevel@tonic-gate 	    e->e_xfp != NULL)
742*7c478bd9Sstevel@tonic-gate 		OutChannel = e->e_xfp;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	/*
745*7c478bd9Sstevel@tonic-gate 	**  Set up some basic system macros.
746*7c478bd9Sstevel@tonic-gate 	*/
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	/* process id */
749*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(buf, sizeof buf, "%d", (int) CurrentPid);
750*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, 'p', buf);
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	/* hop count */
753*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
754*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, 'c', buf);
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	/* time as integer, unix time, arpa time */
757*7c478bd9Sstevel@tonic-gate 	settime(e);
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	/* Load average */
760*7c478bd9Sstevel@tonic-gate 	sm_getla();
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate #ifdef TTYNAME
763*7c478bd9Sstevel@tonic-gate 	/* tty name */
764*7c478bd9Sstevel@tonic-gate 	if (macvalue('y', e) == NULL)
765*7c478bd9Sstevel@tonic-gate 	{
766*7c478bd9Sstevel@tonic-gate 		p = ttyname(2);
767*7c478bd9Sstevel@tonic-gate 		if (p != NULL)
768*7c478bd9Sstevel@tonic-gate 		{
769*7c478bd9Sstevel@tonic-gate 			if (strrchr(p, '/') != NULL)
770*7c478bd9Sstevel@tonic-gate 				p = strrchr(p, '/') + 1;
771*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(ybuf, sizeof ybuf, p);
772*7c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, 'y', ybuf);
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate #endif /* TTYNAME */
776*7c478bd9Sstevel@tonic-gate }
777*7c478bd9Sstevel@tonic-gate /*
778*7c478bd9Sstevel@tonic-gate **  SETTIME -- set the current time.
779*7c478bd9Sstevel@tonic-gate **
780*7c478bd9Sstevel@tonic-gate **	Parameters:
781*7c478bd9Sstevel@tonic-gate **		e -- the envelope in which the macros should be set.
782*7c478bd9Sstevel@tonic-gate **
783*7c478bd9Sstevel@tonic-gate **	Returns:
784*7c478bd9Sstevel@tonic-gate **		none.
785*7c478bd9Sstevel@tonic-gate **
786*7c478bd9Sstevel@tonic-gate **	Side Effects:
787*7c478bd9Sstevel@tonic-gate **		Sets the various time macros -- $a, $b, $d, $t.
788*7c478bd9Sstevel@tonic-gate */
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate void
791*7c478bd9Sstevel@tonic-gate settime(e)
792*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
793*7c478bd9Sstevel@tonic-gate {
794*7c478bd9Sstevel@tonic-gate 	register char *p;
795*7c478bd9Sstevel@tonic-gate 	auto time_t now;
796*7c478bd9Sstevel@tonic-gate 	char buf[30];
797*7c478bd9Sstevel@tonic-gate 	register struct tm *tm;
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	now = curtime();
800*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(buf, sizeof buf, "%ld", (long) now);
801*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, macid("{time}"), buf);
802*7c478bd9Sstevel@tonic-gate 	tm = gmtime(&now);
803*7c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(buf, sizeof buf, "%04d%02d%02d%02d%02d",
804*7c478bd9Sstevel@tonic-gate 			   tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
805*7c478bd9Sstevel@tonic-gate 			   tm->tm_hour, tm->tm_min);
806*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, 't', buf);
807*7c478bd9Sstevel@tonic-gate 	(void) sm_strlcpy(buf, ctime(&now), sizeof buf);
808*7c478bd9Sstevel@tonic-gate 	p = strchr(buf, '\n');
809*7c478bd9Sstevel@tonic-gate 	if (p != NULL)
810*7c478bd9Sstevel@tonic-gate 		*p = '\0';
811*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, 'd', buf);
812*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_TEMP, 'b', arpadate(buf));
813*7c478bd9Sstevel@tonic-gate 	if (macvalue('a', e) == NULL)
814*7c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, 'a', macvalue('b', e));
815*7c478bd9Sstevel@tonic-gate }
816*7c478bd9Sstevel@tonic-gate /*
817*7c478bd9Sstevel@tonic-gate **  OPENXSCRIPT -- Open transcript file
818*7c478bd9Sstevel@tonic-gate **
819*7c478bd9Sstevel@tonic-gate **	Creates a transcript file for possible eventual mailing or
820*7c478bd9Sstevel@tonic-gate **	sending back.
821*7c478bd9Sstevel@tonic-gate **
822*7c478bd9Sstevel@tonic-gate **	Parameters:
823*7c478bd9Sstevel@tonic-gate **		e -- the envelope to create the transcript in/for.
824*7c478bd9Sstevel@tonic-gate **
825*7c478bd9Sstevel@tonic-gate **	Returns:
826*7c478bd9Sstevel@tonic-gate **		none
827*7c478bd9Sstevel@tonic-gate **
828*7c478bd9Sstevel@tonic-gate **	Side Effects:
829*7c478bd9Sstevel@tonic-gate **		Creates the transcript file.
830*7c478bd9Sstevel@tonic-gate */
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate #ifndef O_APPEND
833*7c478bd9Sstevel@tonic-gate # define O_APPEND	0
834*7c478bd9Sstevel@tonic-gate #endif /* ! O_APPEND */
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate void
837*7c478bd9Sstevel@tonic-gate openxscript(e)
838*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
839*7c478bd9Sstevel@tonic-gate {
840*7c478bd9Sstevel@tonic-gate 	register char *p;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	if (e->e_xfp != NULL)
843*7c478bd9Sstevel@tonic-gate 		return;
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate #if 0
846*7c478bd9Sstevel@tonic-gate 	if (e->e_lockfp == NULL && bitset(EF_INQUEUE, e->e_flags))
847*7c478bd9Sstevel@tonic-gate 		syserr("openxscript: job not locked");
848*7c478bd9Sstevel@tonic-gate #endif /* 0 */
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	p = queuename(e, XSCRPT_LETTER);
851*7c478bd9Sstevel@tonic-gate 	e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize,
852*7c478bd9Sstevel@tonic-gate 			  SFF_NOTEXCL|SFF_OPENASROOT);
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	if (e->e_xfp == NULL)
855*7c478bd9Sstevel@tonic-gate 	{
856*7c478bd9Sstevel@tonic-gate 		syserr("Can't create transcript file %s", p);
857*7c478bd9Sstevel@tonic-gate 		e->e_xfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
858*7c478bd9Sstevel@tonic-gate 				      SM_PATH_DEVNULL, SM_IO_RDWR, NULL);
859*7c478bd9Sstevel@tonic-gate 		if (e->e_xfp == NULL)
860*7c478bd9Sstevel@tonic-gate 			syserr("!Can't open %s", SM_PATH_DEVNULL);
861*7c478bd9Sstevel@tonic-gate 	}
862*7c478bd9Sstevel@tonic-gate 	(void) sm_io_setvbuf(e->e_xfp, SM_TIME_DEFAULT, NULL, SM_IO_LBF, 0);
863*7c478bd9Sstevel@tonic-gate 	if (tTd(46, 9))
864*7c478bd9Sstevel@tonic-gate 	{
865*7c478bd9Sstevel@tonic-gate 		sm_dprintf("openxscript(%s):\n  ", p);
866*7c478bd9Sstevel@tonic-gate 		dumpfd(sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL), true,
867*7c478bd9Sstevel@tonic-gate 		       false);
868*7c478bd9Sstevel@tonic-gate 	}
869*7c478bd9Sstevel@tonic-gate }
870*7c478bd9Sstevel@tonic-gate /*
871*7c478bd9Sstevel@tonic-gate **  CLOSEXSCRIPT -- close the transcript file.
872*7c478bd9Sstevel@tonic-gate **
873*7c478bd9Sstevel@tonic-gate **	Parameters:
874*7c478bd9Sstevel@tonic-gate **		e -- the envelope containing the transcript to close.
875*7c478bd9Sstevel@tonic-gate **
876*7c478bd9Sstevel@tonic-gate **	Returns:
877*7c478bd9Sstevel@tonic-gate **		none.
878*7c478bd9Sstevel@tonic-gate **
879*7c478bd9Sstevel@tonic-gate **	Side Effects:
880*7c478bd9Sstevel@tonic-gate **		none.
881*7c478bd9Sstevel@tonic-gate */
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate void
884*7c478bd9Sstevel@tonic-gate closexscript(e)
885*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
886*7c478bd9Sstevel@tonic-gate {
887*7c478bd9Sstevel@tonic-gate 	if (e->e_xfp == NULL)
888*7c478bd9Sstevel@tonic-gate 		return;
889*7c478bd9Sstevel@tonic-gate #if 0
890*7c478bd9Sstevel@tonic-gate 	if (e->e_lockfp == NULL)
891*7c478bd9Sstevel@tonic-gate 		syserr("closexscript: job not locked");
892*7c478bd9Sstevel@tonic-gate #endif /* 0 */
893*7c478bd9Sstevel@tonic-gate 	(void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
894*7c478bd9Sstevel@tonic-gate 	e->e_xfp = NULL;
895*7c478bd9Sstevel@tonic-gate }
896*7c478bd9Sstevel@tonic-gate /*
897*7c478bd9Sstevel@tonic-gate **  SETSENDER -- set the person who this message is from
898*7c478bd9Sstevel@tonic-gate **
899*7c478bd9Sstevel@tonic-gate **	Under certain circumstances allow the user to say who
900*7c478bd9Sstevel@tonic-gate **	s/he is (using -f or -r).  These are:
901*7c478bd9Sstevel@tonic-gate **	1.  The user's uid is zero (root).
902*7c478bd9Sstevel@tonic-gate **	2.  The user's login name is in an approved list (typically
903*7c478bd9Sstevel@tonic-gate **	    from a network server).
904*7c478bd9Sstevel@tonic-gate **	3.  The address the user is trying to claim has a
905*7c478bd9Sstevel@tonic-gate **	    "!" character in it (since #2 doesn't do it for
906*7c478bd9Sstevel@tonic-gate **	    us if we are dialing out for UUCP).
907*7c478bd9Sstevel@tonic-gate **	A better check to replace #3 would be if the
908*7c478bd9Sstevel@tonic-gate **	effective uid is "UUCP" -- this would require me
909*7c478bd9Sstevel@tonic-gate **	to rewrite getpwent to "grab" uucp as it went by,
910*7c478bd9Sstevel@tonic-gate **	make getname more nasty, do another passwd file
911*7c478bd9Sstevel@tonic-gate **	scan, or compile the UID of "UUCP" into the code,
912*7c478bd9Sstevel@tonic-gate **	all of which are reprehensible.
913*7c478bd9Sstevel@tonic-gate **
914*7c478bd9Sstevel@tonic-gate **	Assuming all of these fail, we figure out something
915*7c478bd9Sstevel@tonic-gate **	ourselves.
916*7c478bd9Sstevel@tonic-gate **
917*7c478bd9Sstevel@tonic-gate **	Parameters:
918*7c478bd9Sstevel@tonic-gate **		from -- the person we would like to believe this message
919*7c478bd9Sstevel@tonic-gate **			is from, as specified on the command line.
920*7c478bd9Sstevel@tonic-gate **		e -- the envelope in which we would like the sender set.
921*7c478bd9Sstevel@tonic-gate **		delimptr -- if non-NULL, set to the location of the
922*7c478bd9Sstevel@tonic-gate **			trailing delimiter.
923*7c478bd9Sstevel@tonic-gate **		delimchar -- the character that will delimit the sender
924*7c478bd9Sstevel@tonic-gate **			address.
925*7c478bd9Sstevel@tonic-gate **		internal -- set if this address is coming from an internal
926*7c478bd9Sstevel@tonic-gate **			source such as an owner alias.
927*7c478bd9Sstevel@tonic-gate **
928*7c478bd9Sstevel@tonic-gate **	Returns:
929*7c478bd9Sstevel@tonic-gate **		none.
930*7c478bd9Sstevel@tonic-gate **
931*7c478bd9Sstevel@tonic-gate **	Side Effects:
932*7c478bd9Sstevel@tonic-gate **		sets sendmail's notion of who the from person is.
933*7c478bd9Sstevel@tonic-gate */
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate void
936*7c478bd9Sstevel@tonic-gate setsender(from, e, delimptr, delimchar, internal)
937*7c478bd9Sstevel@tonic-gate 	char *from;
938*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
939*7c478bd9Sstevel@tonic-gate 	char **delimptr;
940*7c478bd9Sstevel@tonic-gate 	int delimchar;
941*7c478bd9Sstevel@tonic-gate 	bool internal;
942*7c478bd9Sstevel@tonic-gate {
943*7c478bd9Sstevel@tonic-gate 	register char **pvp;
944*7c478bd9Sstevel@tonic-gate 	char *realname = NULL;
945*7c478bd9Sstevel@tonic-gate 	char *bp;
946*7c478bd9Sstevel@tonic-gate 	char buf[MAXNAME + 2];
947*7c478bd9Sstevel@tonic-gate 	char pvpbuf[PSBUFSIZE];
948*7c478bd9Sstevel@tonic-gate 	extern char *FullName;
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	if (tTd(45, 1))
951*7c478bd9Sstevel@tonic-gate 		sm_dprintf("setsender(%s)\n", from == NULL ? "" : from);
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	/* may be set from earlier calls */
954*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'x', "");
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	/*
957*7c478bd9Sstevel@tonic-gate 	**  Figure out the real user executing us.
958*7c478bd9Sstevel@tonic-gate 	**	Username can return errno != 0 on non-errors.
959*7c478bd9Sstevel@tonic-gate 	*/
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
962*7c478bd9Sstevel@tonic-gate 	    OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
963*7c478bd9Sstevel@tonic-gate 		realname = from;
964*7c478bd9Sstevel@tonic-gate 	if (realname == NULL || realname[0] == '\0')
965*7c478bd9Sstevel@tonic-gate 		realname = username();
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	if (ConfigLevel < 2)
968*7c478bd9Sstevel@tonic-gate 		SuprErrs = true;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e s");
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	/* preset state for then clause in case from == NULL */
973*7c478bd9Sstevel@tonic-gate 	e->e_from.q_state = QS_BADADDR;
974*7c478bd9Sstevel@tonic-gate 	e->e_from.q_flags = 0;
975*7c478bd9Sstevel@tonic-gate 	if (from == NULL ||
976*7c478bd9Sstevel@tonic-gate 	    parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
977*7c478bd9Sstevel@tonic-gate 		      delimchar, delimptr, e, false) == NULL ||
978*7c478bd9Sstevel@tonic-gate 	    QS_IS_BADADDR(e->e_from.q_state) ||
979*7c478bd9Sstevel@tonic-gate 	    e->e_from.q_mailer == ProgMailer ||
980*7c478bd9Sstevel@tonic-gate 	    e->e_from.q_mailer == FileMailer ||
981*7c478bd9Sstevel@tonic-gate 	    e->e_from.q_mailer == InclMailer)
982*7c478bd9Sstevel@tonic-gate 	{
983*7c478bd9Sstevel@tonic-gate 		/* log garbage addresses for traceback */
984*7c478bd9Sstevel@tonic-gate 		if (from != NULL && LogLevel > 2)
985*7c478bd9Sstevel@tonic-gate 		{
986*7c478bd9Sstevel@tonic-gate 			char *p;
987*7c478bd9Sstevel@tonic-gate 			char ebuf[MAXNAME * 2 + 2];
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 			p = macvalue('_', e);
990*7c478bd9Sstevel@tonic-gate 			if (p == NULL)
991*7c478bd9Sstevel@tonic-gate 			{
992*7c478bd9Sstevel@tonic-gate 				char *host = RealHostName;
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 				if (host == NULL)
995*7c478bd9Sstevel@tonic-gate 					host = MyHostName;
996*7c478bd9Sstevel@tonic-gate 				(void) sm_snprintf(ebuf, sizeof ebuf,
997*7c478bd9Sstevel@tonic-gate 						   "%.*s@%.*s", MAXNAME,
998*7c478bd9Sstevel@tonic-gate 						   realname, MAXNAME, host);
999*7c478bd9Sstevel@tonic-gate 				p = ebuf;
1000*7c478bd9Sstevel@tonic-gate 			}
1001*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_NOTICE, e->e_id,
1002*7c478bd9Sstevel@tonic-gate 				  "setsender: %s: invalid or unparsable, received from %s",
1003*7c478bd9Sstevel@tonic-gate 				  shortenstring(from, 83), p);
1004*7c478bd9Sstevel@tonic-gate 		}
1005*7c478bd9Sstevel@tonic-gate 		if (from != NULL)
1006*7c478bd9Sstevel@tonic-gate 		{
1007*7c478bd9Sstevel@tonic-gate 			if (!QS_IS_BADADDR(e->e_from.q_state))
1008*7c478bd9Sstevel@tonic-gate 			{
1009*7c478bd9Sstevel@tonic-gate 				/* it was a bogus mailer in the from addr */
1010*7c478bd9Sstevel@tonic-gate 				e->e_status = "5.1.7";
1011*7c478bd9Sstevel@tonic-gate 				usrerrenh(e->e_status,
1012*7c478bd9Sstevel@tonic-gate 					  "553 Invalid sender address");
1013*7c478bd9Sstevel@tonic-gate 			}
1014*7c478bd9Sstevel@tonic-gate 			SuprErrs = true;
1015*7c478bd9Sstevel@tonic-gate 		}
1016*7c478bd9Sstevel@tonic-gate 		if (from == realname ||
1017*7c478bd9Sstevel@tonic-gate 		    parseaddr(from = realname,
1018*7c478bd9Sstevel@tonic-gate 			      &e->e_from, RF_COPYALL|RF_SENDERADDR, ' ',
1019*7c478bd9Sstevel@tonic-gate 			      NULL, e, false) == NULL)
1020*7c478bd9Sstevel@tonic-gate 		{
1021*7c478bd9Sstevel@tonic-gate 			char nbuf[100];
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 			SuprErrs = true;
1024*7c478bd9Sstevel@tonic-gate 			expand("\201n", nbuf, sizeof nbuf, e);
1025*7c478bd9Sstevel@tonic-gate 			from = sm_rpool_strdup_x(e->e_rpool, nbuf);
1026*7c478bd9Sstevel@tonic-gate 			if (parseaddr(from, &e->e_from, RF_COPYALL, ' ',
1027*7c478bd9Sstevel@tonic-gate 				      NULL, e, false) == NULL &&
1028*7c478bd9Sstevel@tonic-gate 			    parseaddr(from = "postmaster", &e->e_from,
1029*7c478bd9Sstevel@tonic-gate 				      RF_COPYALL, ' ', NULL, e, false) == NULL)
1030*7c478bd9Sstevel@tonic-gate 				syserr("553 5.3.0 setsender: can't even parse postmaster!");
1031*7c478bd9Sstevel@tonic-gate 		}
1032*7c478bd9Sstevel@tonic-gate 	}
1033*7c478bd9Sstevel@tonic-gate 	else
1034*7c478bd9Sstevel@tonic-gate 		FromFlag = true;
1035*7c478bd9Sstevel@tonic-gate 	e->e_from.q_state = QS_SENDER;
1036*7c478bd9Sstevel@tonic-gate 	if (tTd(45, 5))
1037*7c478bd9Sstevel@tonic-gate 	{
1038*7c478bd9Sstevel@tonic-gate 		sm_dprintf("setsender: QS_SENDER ");
1039*7c478bd9Sstevel@tonic-gate 		printaddr(sm_debug_file(), &e->e_from, false);
1040*7c478bd9Sstevel@tonic-gate 	}
1041*7c478bd9Sstevel@tonic-gate 	SuprErrs = false;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate #if USERDB
1044*7c478bd9Sstevel@tonic-gate 	if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
1045*7c478bd9Sstevel@tonic-gate 	{
1046*7c478bd9Sstevel@tonic-gate 		register char *p;
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate 		p = udbsender(e->e_from.q_user, e->e_rpool);
1049*7c478bd9Sstevel@tonic-gate 		if (p != NULL)
1050*7c478bd9Sstevel@tonic-gate 			from = p;
1051*7c478bd9Sstevel@tonic-gate 	}
1052*7c478bd9Sstevel@tonic-gate #endif /* USERDB */
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
1055*7c478bd9Sstevel@tonic-gate 	{
1056*7c478bd9Sstevel@tonic-gate 		SM_MBDB_T user;
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 		if (!internal)
1059*7c478bd9Sstevel@tonic-gate 		{
1060*7c478bd9Sstevel@tonic-gate 			/* if the user already given fullname don't redefine */
1061*7c478bd9Sstevel@tonic-gate 			if (FullName == NULL)
1062*7c478bd9Sstevel@tonic-gate 				FullName = macvalue('x', e);
1063*7c478bd9Sstevel@tonic-gate 			if (FullName != NULL)
1064*7c478bd9Sstevel@tonic-gate 			{
1065*7c478bd9Sstevel@tonic-gate 				if (FullName[0] == '\0')
1066*7c478bd9Sstevel@tonic-gate 					FullName = NULL;
1067*7c478bd9Sstevel@tonic-gate 				else
1068*7c478bd9Sstevel@tonic-gate 					FullName = newstr(FullName);
1069*7c478bd9Sstevel@tonic-gate 			}
1070*7c478bd9Sstevel@tonic-gate 		}
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 		if (e->e_from.q_user[0] != '\0' &&
1073*7c478bd9Sstevel@tonic-gate 		    sm_mbdb_lookup(e->e_from.q_user, &user) == EX_OK)
1074*7c478bd9Sstevel@tonic-gate 		{
1075*7c478bd9Sstevel@tonic-gate 			/*
1076*7c478bd9Sstevel@tonic-gate 			**  Process passwd file entry.
1077*7c478bd9Sstevel@tonic-gate 			*/
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 			/* extract home directory */
1080*7c478bd9Sstevel@tonic-gate 			if (*user.mbdb_homedir == '\0')
1081*7c478bd9Sstevel@tonic-gate 				e->e_from.q_home = NULL;
1082*7c478bd9Sstevel@tonic-gate 			else if (strcmp(user.mbdb_homedir, "/") == 0)
1083*7c478bd9Sstevel@tonic-gate 				e->e_from.q_home = "";
1084*7c478bd9Sstevel@tonic-gate 			else
1085*7c478bd9Sstevel@tonic-gate 				e->e_from.q_home = sm_rpool_strdup_x(e->e_rpool,
1086*7c478bd9Sstevel@tonic-gate 							user.mbdb_homedir);
1087*7c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, 'z', e->e_from.q_home);
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 			/* extract user and group id */
1090*7c478bd9Sstevel@tonic-gate 			if (user.mbdb_uid != SM_NO_UID)
1091*7c478bd9Sstevel@tonic-gate 			{
1092*7c478bd9Sstevel@tonic-gate 				e->e_from.q_uid = user.mbdb_uid;
1093*7c478bd9Sstevel@tonic-gate 				e->e_from.q_gid = user.mbdb_gid;
1094*7c478bd9Sstevel@tonic-gate 				e->e_from.q_flags |= QGOODUID;
1095*7c478bd9Sstevel@tonic-gate 			}
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 			/* extract full name from passwd file */
1098*7c478bd9Sstevel@tonic-gate 			if (FullName == NULL && !internal &&
1099*7c478bd9Sstevel@tonic-gate 			    user.mbdb_fullname[0] != '\0' &&
1100*7c478bd9Sstevel@tonic-gate 			    strcmp(user.mbdb_name, e->e_from.q_user) == 0)
1101*7c478bd9Sstevel@tonic-gate 			{
1102*7c478bd9Sstevel@tonic-gate 				FullName = newstr(user.mbdb_fullname);
1103*7c478bd9Sstevel@tonic-gate 			}
1104*7c478bd9Sstevel@tonic-gate 		}
1105*7c478bd9Sstevel@tonic-gate 		else
1106*7c478bd9Sstevel@tonic-gate 		{
1107*7c478bd9Sstevel@tonic-gate 			e->e_from.q_home = NULL;
1108*7c478bd9Sstevel@tonic-gate 		}
1109*7c478bd9Sstevel@tonic-gate 		if (FullName != NULL && !internal)
1110*7c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_TEMP, 'x', FullName);
1111*7c478bd9Sstevel@tonic-gate 	}
1112*7c478bd9Sstevel@tonic-gate 	else if (!internal && OpMode != MD_DAEMON && OpMode != MD_SMTP)
1113*7c478bd9Sstevel@tonic-gate 	{
1114*7c478bd9Sstevel@tonic-gate 		if (e->e_from.q_home == NULL)
1115*7c478bd9Sstevel@tonic-gate 		{
1116*7c478bd9Sstevel@tonic-gate 			e->e_from.q_home = getenv("HOME");
1117*7c478bd9Sstevel@tonic-gate 			if (e->e_from.q_home != NULL)
1118*7c478bd9Sstevel@tonic-gate 			{
1119*7c478bd9Sstevel@tonic-gate 				if (*e->e_from.q_home == '\0')
1120*7c478bd9Sstevel@tonic-gate 					e->e_from.q_home = NULL;
1121*7c478bd9Sstevel@tonic-gate 				else if (strcmp(e->e_from.q_home, "/") == 0)
1122*7c478bd9Sstevel@tonic-gate 					e->e_from.q_home++;
1123*7c478bd9Sstevel@tonic-gate 			}
1124*7c478bd9Sstevel@tonic-gate 		}
1125*7c478bd9Sstevel@tonic-gate 		e->e_from.q_uid = RealUid;
1126*7c478bd9Sstevel@tonic-gate 		e->e_from.q_gid = RealGid;
1127*7c478bd9Sstevel@tonic-gate 		e->e_from.q_flags |= QGOODUID;
1128*7c478bd9Sstevel@tonic-gate 	}
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	/*
1131*7c478bd9Sstevel@tonic-gate 	**  Rewrite the from person to dispose of possible implicit
1132*7c478bd9Sstevel@tonic-gate 	**	links in the net.
1133*7c478bd9Sstevel@tonic-gate 	*/
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL, false);
1136*7c478bd9Sstevel@tonic-gate 	if (pvp == NULL)
1137*7c478bd9Sstevel@tonic-gate 	{
1138*7c478bd9Sstevel@tonic-gate 		/* don't need to give error -- prescan did that already */
1139*7c478bd9Sstevel@tonic-gate 		if (LogLevel > 2)
1140*7c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_NOTICE, e->e_id,
1141*7c478bd9Sstevel@tonic-gate 				  "cannot prescan from (%s)",
1142*7c478bd9Sstevel@tonic-gate 				  shortenstring(from, MAXSHORTSTR));
1143*7c478bd9Sstevel@tonic-gate 		finis(true, true, ExitStat);
1144*7c478bd9Sstevel@tonic-gate 	}
1145*7c478bd9Sstevel@tonic-gate 	(void) REWRITE(pvp, 3, e);
1146*7c478bd9Sstevel@tonic-gate 	(void) REWRITE(pvp, 1, e);
1147*7c478bd9Sstevel@tonic-gate 	(void) REWRITE(pvp, 4, e);
1148*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
1149*7c478bd9Sstevel@tonic-gate 	bp = buf + 1;
1150*7c478bd9Sstevel@tonic-gate 	cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
1151*7c478bd9Sstevel@tonic-gate 	if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
1152*7c478bd9Sstevel@tonic-gate 	{
1153*7c478bd9Sstevel@tonic-gate 		/* heuristic: route-addr: add angle brackets */
1154*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcat(bp, ">", sizeof buf - 1);
1155*7c478bd9Sstevel@tonic-gate 		*--bp = '<';
1156*7c478bd9Sstevel@tonic-gate 	}
1157*7c478bd9Sstevel@tonic-gate 	e->e_sender = sm_rpool_strdup_x(e->e_rpool, bp);
1158*7c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	/* save the domain spec if this mailer wants it */
1161*7c478bd9Sstevel@tonic-gate 	if (e->e_from.q_mailer != NULL &&
1162*7c478bd9Sstevel@tonic-gate 	    bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
1163*7c478bd9Sstevel@tonic-gate 	{
1164*7c478bd9Sstevel@tonic-gate 		char **lastat;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 		/* get rid of any pesky angle brackets */
1167*7c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e s");
1168*7c478bd9Sstevel@tonic-gate 		(void) REWRITE(pvp, 3, e);
1169*7c478bd9Sstevel@tonic-gate 		(void) REWRITE(pvp, 1, e);
1170*7c478bd9Sstevel@tonic-gate 		(void) REWRITE(pvp, 4, e);
1171*7c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 		/* strip off to the last "@" sign */
1174*7c478bd9Sstevel@tonic-gate 		for (lastat = NULL; *pvp != NULL; pvp++)
1175*7c478bd9Sstevel@tonic-gate 		{
1176*7c478bd9Sstevel@tonic-gate 			if (strcmp(*pvp, "@") == 0)
1177*7c478bd9Sstevel@tonic-gate 				lastat = pvp;
1178*7c478bd9Sstevel@tonic-gate 		}
1179*7c478bd9Sstevel@tonic-gate 		if (lastat != NULL)
1180*7c478bd9Sstevel@tonic-gate 		{
1181*7c478bd9Sstevel@tonic-gate 			e->e_fromdomain = copyplist(lastat, true, e->e_rpool);
1182*7c478bd9Sstevel@tonic-gate 			if (tTd(45, 3))
1183*7c478bd9Sstevel@tonic-gate 			{
1184*7c478bd9Sstevel@tonic-gate 				sm_dprintf("Saving from domain: ");
1185*7c478bd9Sstevel@tonic-gate 				printav(sm_debug_file(), e->e_fromdomain);
1186*7c478bd9Sstevel@tonic-gate 			}
1187*7c478bd9Sstevel@tonic-gate 		}
1188*7c478bd9Sstevel@tonic-gate 	}
1189*7c478bd9Sstevel@tonic-gate }
1190*7c478bd9Sstevel@tonic-gate /*
1191*7c478bd9Sstevel@tonic-gate **  PRINTENVFLAGS -- print envelope flags for debugging
1192*7c478bd9Sstevel@tonic-gate **
1193*7c478bd9Sstevel@tonic-gate **	Parameters:
1194*7c478bd9Sstevel@tonic-gate **		e -- the envelope with the flags to be printed.
1195*7c478bd9Sstevel@tonic-gate **
1196*7c478bd9Sstevel@tonic-gate **	Returns:
1197*7c478bd9Sstevel@tonic-gate **		none.
1198*7c478bd9Sstevel@tonic-gate */
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate struct eflags
1201*7c478bd9Sstevel@tonic-gate {
1202*7c478bd9Sstevel@tonic-gate 	char		*ef_name;
1203*7c478bd9Sstevel@tonic-gate 	unsigned long	ef_bit;
1204*7c478bd9Sstevel@tonic-gate };
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate static struct eflags	EnvelopeFlags[] =
1207*7c478bd9Sstevel@tonic-gate {
1208*7c478bd9Sstevel@tonic-gate 	{ "OLDSTYLE",		EF_OLDSTYLE	},
1209*7c478bd9Sstevel@tonic-gate 	{ "INQUEUE",		EF_INQUEUE	},
1210*7c478bd9Sstevel@tonic-gate 	{ "NO_BODY_RETN",	EF_NO_BODY_RETN	},
1211*7c478bd9Sstevel@tonic-gate 	{ "CLRQUEUE",		EF_CLRQUEUE	},
1212*7c478bd9Sstevel@tonic-gate 	{ "SENDRECEIPT",	EF_SENDRECEIPT	},
1213*7c478bd9Sstevel@tonic-gate 	{ "FATALERRS",		EF_FATALERRS	},
1214*7c478bd9Sstevel@tonic-gate 	{ "DELETE_BCC",		EF_DELETE_BCC	},
1215*7c478bd9Sstevel@tonic-gate 	{ "RESPONSE",		EF_RESPONSE	},
1216*7c478bd9Sstevel@tonic-gate 	{ "RESENT",		EF_RESENT	},
1217*7c478bd9Sstevel@tonic-gate 	{ "VRFYONLY",		EF_VRFYONLY	},
1218*7c478bd9Sstevel@tonic-gate 	{ "WARNING",		EF_WARNING	},
1219*7c478bd9Sstevel@tonic-gate 	{ "QUEUERUN",		EF_QUEUERUN	},
1220*7c478bd9Sstevel@tonic-gate 	{ "GLOBALERRS",		EF_GLOBALERRS	},
1221*7c478bd9Sstevel@tonic-gate 	{ "PM_NOTIFY",		EF_PM_NOTIFY	},
1222*7c478bd9Sstevel@tonic-gate 	{ "METOO",		EF_METOO	},
1223*7c478bd9Sstevel@tonic-gate 	{ "LOGSENDER",		EF_LOGSENDER	},
1224*7c478bd9Sstevel@tonic-gate 	{ "NORECEIPT",		EF_NORECEIPT	},
1225*7c478bd9Sstevel@tonic-gate 	{ "HAS8BIT",		EF_HAS8BIT	},
1226*7c478bd9Sstevel@tonic-gate 	{ "NL_NOT_EOL",		EF_NL_NOT_EOL	},
1227*7c478bd9Sstevel@tonic-gate 	{ "CRLF_NOT_EOL",	EF_CRLF_NOT_EOL	},
1228*7c478bd9Sstevel@tonic-gate 	{ "RET_PARAM",		EF_RET_PARAM	},
1229*7c478bd9Sstevel@tonic-gate 	{ "HAS_DF",		EF_HAS_DF	},
1230*7c478bd9Sstevel@tonic-gate 	{ "IS_MIME",		EF_IS_MIME	},
1231*7c478bd9Sstevel@tonic-gate 	{ "DONT_MIME",		EF_DONT_MIME	},
1232*7c478bd9Sstevel@tonic-gate 	{ "DISCARD",		EF_DISCARD	},
1233*7c478bd9Sstevel@tonic-gate 	{ "TOOBIG",		EF_TOOBIG	},
1234*7c478bd9Sstevel@tonic-gate 	{ "SPLIT",		EF_SPLIT	},
1235*7c478bd9Sstevel@tonic-gate 	{ "UNSAFE",		EF_UNSAFE	},
1236*7c478bd9Sstevel@tonic-gate 	{ NULL,			0		}
1237*7c478bd9Sstevel@tonic-gate };
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate void
1240*7c478bd9Sstevel@tonic-gate printenvflags(e)
1241*7c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
1242*7c478bd9Sstevel@tonic-gate {
1243*7c478bd9Sstevel@tonic-gate 	register struct eflags *ef;
1244*7c478bd9Sstevel@tonic-gate 	bool first = true;
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	sm_dprintf("%lx", e->e_flags);
1247*7c478bd9Sstevel@tonic-gate 	for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
1248*7c478bd9Sstevel@tonic-gate 	{
1249*7c478bd9Sstevel@tonic-gate 		if (!bitset(ef->ef_bit, e->e_flags))
1250*7c478bd9Sstevel@tonic-gate 			continue;
1251*7c478bd9Sstevel@tonic-gate 		if (first)
1252*7c478bd9Sstevel@tonic-gate 			sm_dprintf("<%s", ef->ef_name);
1253*7c478bd9Sstevel@tonic-gate 		else
1254*7c478bd9Sstevel@tonic-gate 			sm_dprintf(",%s", ef->ef_name);
1255*7c478bd9Sstevel@tonic-gate 		first = false;
1256*7c478bd9Sstevel@tonic-gate 	}
1257*7c478bd9Sstevel@tonic-gate 	if (!first)
1258*7c478bd9Sstevel@tonic-gate 		sm_dprintf(">\n");
1259*7c478bd9Sstevel@tonic-gate }
1260