xref: /plan9-contrib/sys/src/cmd/upas/send/main.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include "common.h"
23e12c5d1SDavid du Colombier #include "send.h"
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier /* globals to all files */
53e12c5d1SDavid du Colombier int rmail;
6*219b2ee8SDavid du Colombier char *thissys, *altthissys;
73e12c5d1SDavid du Colombier int nflg;
83e12c5d1SDavid du Colombier int xflg;
93e12c5d1SDavid du Colombier int debug;
103e12c5d1SDavid du Colombier int rflg;
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier /* global to this file */
133e12c5d1SDavid du Colombier static String *errstring;
143e12c5d1SDavid du Colombier static message *mp;
153e12c5d1SDavid du Colombier static int interrupt;
163e12c5d1SDavid du Colombier static int savemail;
173e12c5d1SDavid du Colombier static Biobuf in;
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier /* predeclared */
203e12c5d1SDavid du Colombier static int	send(dest *, message *, int);
213e12c5d1SDavid du Colombier static void	lesstedious(void);
223e12c5d1SDavid du Colombier static void	save_mail(message *);
233e12c5d1SDavid du Colombier static int	complain_mail(dest *, message *);
243e12c5d1SDavid du Colombier static int	pipe_mail(dest *, message *);
253e12c5d1SDavid du Colombier static int	cat_mail(dest *, message *);
263e12c5d1SDavid du Colombier static void	appaddr(String *, dest *);
273e12c5d1SDavid du Colombier static int	refuse(dest *, message *, char *, int);
283e12c5d1SDavid du Colombier static void	mkerrstring(String *, message *, dest *, dest *, char *, int);
293e12c5d1SDavid du Colombier static int	replymsg(String *, message *, dest *);
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier void
323e12c5d1SDavid du Colombier main(int argc, char *argv[])
333e12c5d1SDavid du Colombier {
343e12c5d1SDavid du Colombier 	dest *dp=0;
353e12c5d1SDavid du Colombier 	int checkforward;
363e12c5d1SDavid du Colombier 	char *base;
37*219b2ee8SDavid du Colombier 	int rv, holding;
38*219b2ee8SDavid du Colombier 
39*219b2ee8SDavid du Colombier 	srand(time(0));
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier 	/* process args */
423e12c5d1SDavid du Colombier 	ARGBEGIN{
433e12c5d1SDavid du Colombier 	case '#':
443e12c5d1SDavid du Colombier 		nflg = 1;
453e12c5d1SDavid du Colombier 		break;
463e12c5d1SDavid du Colombier 	case 'x':
473e12c5d1SDavid du Colombier 		nflg = 1;
483e12c5d1SDavid du Colombier 		xflg = 1;
493e12c5d1SDavid du Colombier 		break;
503e12c5d1SDavid du Colombier 	case 'd':
513e12c5d1SDavid du Colombier 		debug = 1;
523e12c5d1SDavid du Colombier 		break;
533e12c5d1SDavid du Colombier 	case 'r':
543e12c5d1SDavid du Colombier 		rflg = 1;
553e12c5d1SDavid du Colombier 		break;
563e12c5d1SDavid du Colombier 	default:
573e12c5d1SDavid du Colombier 		fprint(2, "usage: mail [-x] list-of-addresses\n");
583e12c5d1SDavid du Colombier 		exit(1);
593e12c5d1SDavid du Colombier 	}ARGEND
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier 	while(*argv)
623e12c5d1SDavid du Colombier 		d_insert(&dp, d_new(s_copy(*argv++)));
633e12c5d1SDavid du Colombier 
643e12c5d1SDavid du Colombier 	if (dp == 0) {
653e12c5d1SDavid du Colombier 		fprint(2, "usage: mail [-#] address-list\n");
663e12c5d1SDavid du Colombier 		exit(1);
673e12c5d1SDavid du Colombier 	}
683e12c5d1SDavid du Colombier 
693e12c5d1SDavid du Colombier 	/*
703e12c5d1SDavid du Colombier 	 * get context:
713e12c5d1SDavid du Colombier 	 *	- whether we're rmail or mail
723e12c5d1SDavid du Colombier 	 */
733e12c5d1SDavid du Colombier 	base = basename(argv0);
743e12c5d1SDavid du Colombier 	checkforward = rmail = (strcmp(base, "rmail")==0) | rflg;
753e12c5d1SDavid du Colombier 	thissys = sysname_read();
76*219b2ee8SDavid du Colombier 	altthissys = alt_sysname_read();
773e12c5d1SDavid du Colombier 
783e12c5d1SDavid du Colombier 	/*
793e12c5d1SDavid du Colombier 	 *  read the mail.  If an interrupt occurs while reading, save in
803e12c5d1SDavid du Colombier 	 *  dead.letter
813e12c5d1SDavid du Colombier 	 */
823e12c5d1SDavid du Colombier 	if (!nflg) {
833e12c5d1SDavid du Colombier 		Binit(&in, 0, OREAD);
84*219b2ee8SDavid du Colombier 		if(rmail)
853e12c5d1SDavid du Colombier 			mp = m_read(&in, rmail);
86*219b2ee8SDavid du Colombier 		else {
87*219b2ee8SDavid du Colombier 			holding = holdon();
88*219b2ee8SDavid du Colombier 			mp = m_read(&in, rmail);
89*219b2ee8SDavid du Colombier 			holdoff(holding);
90*219b2ee8SDavid du Colombier 		}
913e12c5d1SDavid du Colombier 		if (mp == 0)
923e12c5d1SDavid du Colombier 			exit(0);
933e12c5d1SDavid du Colombier 		if (interrupt != 0) {
943e12c5d1SDavid du Colombier 			save_mail(mp);
953e12c5d1SDavid du Colombier 			exit(1);
963e12c5d1SDavid du Colombier 		}
973e12c5d1SDavid du Colombier 	} else {
983e12c5d1SDavid du Colombier 		mp = m_new();
993e12c5d1SDavid du Colombier 		default_from(mp);
1003e12c5d1SDavid du Colombier 	}
1013e12c5d1SDavid du Colombier 	errstring = s_new();
1023e12c5d1SDavid du Colombier 	getrules();
1033e12c5d1SDavid du Colombier 
1043e12c5d1SDavid du Colombier 	/*
1053e12c5d1SDavid du Colombier 	 *  If this is a gateway, translate the sender address into a local
1063e12c5d1SDavid du Colombier 	 *  address.  This only happens if mail to the local address is
1073e12c5d1SDavid du Colombier 	 *  forwarded to the sender.
1083e12c5d1SDavid du Colombier 	 */
1093e12c5d1SDavid du Colombier 	gateway(mp);
1103e12c5d1SDavid du Colombier 
1113e12c5d1SDavid du Colombier 	/*
1123e12c5d1SDavid du Colombier 	 *  Protect against shell characters in the sender name for
1133e12c5d1SDavid du Colombier 	 *  security reasons.
1143e12c5d1SDavid du Colombier 	 */
1153e12c5d1SDavid du Colombier 	USE(s_restart(mp->sender));
1163e12c5d1SDavid du Colombier 	if (shellchars(s_to_c(mp->sender)))
1173e12c5d1SDavid du Colombier 		mp->replyaddr = s_copy("postmaster");
1183e12c5d1SDavid du Colombier 	else
1193e12c5d1SDavid du Colombier 		mp->replyaddr = s_clone(mp->sender);
1203e12c5d1SDavid du Colombier 	USE(s_restart(mp->replyaddr));
1213e12c5d1SDavid du Colombier 
1223e12c5d1SDavid du Colombier 	/*
1233e12c5d1SDavid du Colombier 	 *  reject messages that are too long.  We don't do it earlier
1243e12c5d1SDavid du Colombier 	 *  in m_read since we haven't set up enough things yet.
1253e12c5d1SDavid du Colombier 	 */
1263e12c5d1SDavid du Colombier 	if(mp->size < 0)
1273e12c5d1SDavid du Colombier 		exit(refuse(dp, mp, "message too long", 0));
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier 	rv = send(dp, mp, checkforward);
1303e12c5d1SDavid du Colombier 	if(savemail)
1313e12c5d1SDavid du Colombier 		save_mail(mp);
1323e12c5d1SDavid du Colombier 	if(mp)
1333e12c5d1SDavid du Colombier 		m_free(mp);
1343e12c5d1SDavid du Colombier 	exit(rv);
1353e12c5d1SDavid du Colombier }
1363e12c5d1SDavid du Colombier 
1373e12c5d1SDavid du Colombier 
138*219b2ee8SDavid du Colombier 
1393e12c5d1SDavid du Colombier /* send a message to a list of sites */
1403e12c5d1SDavid du Colombier static int
1413e12c5d1SDavid du Colombier send(dest *destp, message *mp, int checkforward)
1423e12c5d1SDavid du Colombier {
1433e12c5d1SDavid du Colombier 	dest *dp;		/* destination being acted upon */
1443e12c5d1SDavid du Colombier 	dest *bound;		/* bound destinations */
1453e12c5d1SDavid du Colombier 	int errors=0;
1463e12c5d1SDavid du Colombier 	static int forked;
1473e12c5d1SDavid du Colombier 
1483e12c5d1SDavid du Colombier 	/* bind the destinations to actions */
1493e12c5d1SDavid du Colombier 	bound = up_bind(destp, mp, checkforward);
1503e12c5d1SDavid du Colombier 
1513e12c5d1SDavid du Colombier 	/* loop through and execute commands */
1523e12c5d1SDavid du Colombier 	for (dp = d_rm(&bound); dp != 0; dp = d_rm(&bound)) {
1533e12c5d1SDavid du Colombier 		switch (dp->status) {
1543e12c5d1SDavid du Colombier 		case d_cat:
1553e12c5d1SDavid du Colombier 			errors += cat_mail(dp, mp);
1563e12c5d1SDavid du Colombier 			break;
1573e12c5d1SDavid du Colombier 		case d_pipeto:
1583e12c5d1SDavid du Colombier 		case d_pipe:
1593e12c5d1SDavid du Colombier 			if (!rmail && !nflg && !forked) {
1603e12c5d1SDavid du Colombier 				forked = 1;
1613e12c5d1SDavid du Colombier 				lesstedious();
1623e12c5d1SDavid du Colombier 			}
1633e12c5d1SDavid du Colombier 			errors += pipe_mail(dp, mp);
1643e12c5d1SDavid du Colombier 			break;
1653e12c5d1SDavid du Colombier 		default:
1663e12c5d1SDavid du Colombier 			errors += complain_mail(dp, mp);
1673e12c5d1SDavid du Colombier 			break;
1683e12c5d1SDavid du Colombier 		}
1693e12c5d1SDavid du Colombier 	}
1703e12c5d1SDavid du Colombier 
1713e12c5d1SDavid du Colombier 	return errors;
1723e12c5d1SDavid du Colombier }
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier /* avoid user tedium (as Mike Lesk said in a previous version) */
1753e12c5d1SDavid du Colombier static void
1763e12c5d1SDavid du Colombier lesstedious(void)
1773e12c5d1SDavid du Colombier {
1783e12c5d1SDavid du Colombier 	int i;
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier 	if(debug)
1813e12c5d1SDavid du Colombier 		return;
182*219b2ee8SDavid du Colombier 
1833e12c5d1SDavid du Colombier 	switch(fork()){
1843e12c5d1SDavid du Colombier 	case -1:
1853e12c5d1SDavid du Colombier 		break;
1863e12c5d1SDavid du Colombier 	case 0:
1873e12c5d1SDavid du Colombier 		rfork(RFENVG|RFNAMEG|RFNOTEG);
1883e12c5d1SDavid du Colombier 		for(i=0; i<nsysfile; i++)
1893e12c5d1SDavid du Colombier 			close(i);
1903e12c5d1SDavid du Colombier 		savemail = 0;
1913e12c5d1SDavid du Colombier 		break;
1923e12c5d1SDavid du Colombier 	default:
1933e12c5d1SDavid du Colombier 		exit(0);
1943e12c5d1SDavid du Colombier 	}
1953e12c5d1SDavid du Colombier }
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier /* save the mail */
1993e12c5d1SDavid du Colombier static void
2003e12c5d1SDavid du Colombier save_mail(message *mp)
2013e12c5d1SDavid du Colombier {
2023e12c5d1SDavid du Colombier 	Biobuf *fp;
2033e12c5d1SDavid du Colombier 	String *file;
2043e12c5d1SDavid du Colombier 	static saved = 0;
2053e12c5d1SDavid du Colombier 
2063e12c5d1SDavid du Colombier 	file = s_new();
2073e12c5d1SDavid du Colombier 	mboxpath("dead.letter", getlog(), file, 0);
2083e12c5d1SDavid du Colombier 	if ((fp = sysopen(s_to_c(file), "cA", 0660)) == 0)
2093e12c5d1SDavid du Colombier 		return;
2103e12c5d1SDavid du Colombier 	m_bprint(mp, fp);
2113e12c5d1SDavid du Colombier 	sysclose(fp);
2123e12c5d1SDavid du Colombier 	fprint(2, "saved in %s\n", s_to_c(file));
2133e12c5d1SDavid du Colombier 	s_free(file);
2143e12c5d1SDavid du Colombier }
2153e12c5d1SDavid du Colombier 
2163e12c5d1SDavid du Colombier /* remember the interrupt happened */
2173e12c5d1SDavid du Colombier /* dispose of incorrect addresses */
2183e12c5d1SDavid du Colombier static int
2193e12c5d1SDavid du Colombier complain_mail(dest *dp, message *mp)
2203e12c5d1SDavid du Colombier {
2213e12c5d1SDavid du Colombier 	char *msg;
2223e12c5d1SDavid du Colombier 
2233e12c5d1SDavid du Colombier 	switch (dp->status) {
2243e12c5d1SDavid du Colombier 	case d_undefined:
2253e12c5d1SDavid du Colombier 		msg = "Invalid address"; /* a little different, for debugging */
2263e12c5d1SDavid du Colombier 		break;
2273e12c5d1SDavid du Colombier 	case d_syntax:
2283e12c5d1SDavid du Colombier 		msg = "invalid address";
2293e12c5d1SDavid du Colombier 		break;
2303e12c5d1SDavid du Colombier 	case d_unknown:
2313e12c5d1SDavid du Colombier 		msg = "unknown user";
2323e12c5d1SDavid du Colombier 		break;
2333e12c5d1SDavid du Colombier 	case d_eloop:
2343e12c5d1SDavid du Colombier 	case d_loop:
2353e12c5d1SDavid du Colombier 		msg = "forwarding loop";
2363e12c5d1SDavid du Colombier 		break;
2373e12c5d1SDavid du Colombier 	case d_noforward:
2383e12c5d1SDavid du Colombier 		if(dp->pstat && *s_to_c(dp->repl2))
2393e12c5d1SDavid du Colombier 			return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat);
2403e12c5d1SDavid du Colombier 		else
2413e12c5d1SDavid du Colombier 			msg = "destination unknown or forwarding disallowed";
2423e12c5d1SDavid du Colombier 		break;
2433e12c5d1SDavid du Colombier 	case d_pipe:
2443e12c5d1SDavid du Colombier 		msg = "broken pipe";
2453e12c5d1SDavid du Colombier 		break;
2463e12c5d1SDavid du Colombier 	case d_cat:
2473e12c5d1SDavid du Colombier 		msg = "broken cat";
2483e12c5d1SDavid du Colombier 		break;
2493e12c5d1SDavid du Colombier 	case d_translate:
2503e12c5d1SDavid du Colombier 		if(dp->pstat && *s_to_c(dp->repl2))
2513e12c5d1SDavid du Colombier 			return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat);
2523e12c5d1SDavid du Colombier 		else
2533e12c5d1SDavid du Colombier 			msg = "name translation failed";
2543e12c5d1SDavid du Colombier 		break;
2553e12c5d1SDavid du Colombier 	case d_alias:
2563e12c5d1SDavid du Colombier 		msg = "broken alias";
2573e12c5d1SDavid du Colombier 		break;
2583e12c5d1SDavid du Colombier 	case d_badmbox:
2593e12c5d1SDavid du Colombier 		msg = "corrupted mailbox";
2603e12c5d1SDavid du Colombier 		break;
2613e12c5d1SDavid du Colombier 	case d_resource:
2623e12c5d1SDavid du Colombier 		msg = "out of some resource.  Try again later.";
2633e12c5d1SDavid du Colombier 		break;
2643e12c5d1SDavid du Colombier 	default:
2653e12c5d1SDavid du Colombier 		msg = "unknown d_";
2663e12c5d1SDavid du Colombier 		break;
2673e12c5d1SDavid du Colombier 	}
2683e12c5d1SDavid du Colombier 	if (nflg) {
2693e12c5d1SDavid du Colombier 		print("%s: %s\n", msg, s_to_c(dp->addr));
2703e12c5d1SDavid du Colombier 		return 0;
2713e12c5d1SDavid du Colombier 	}
2723e12c5d1SDavid du Colombier 	return refuse(dp, mp, msg, 0);
2733e12c5d1SDavid du Colombier }
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier /* dispose of remote addresses */
2763e12c5d1SDavid du Colombier static int
2773e12c5d1SDavid du Colombier pipe_mail(dest *dp, message *mp)
2783e12c5d1SDavid du Colombier {
2793e12c5d1SDavid du Colombier 	String *file;
2803e12c5d1SDavid du Colombier 	dest *next, *list=0;
2813e12c5d1SDavid du Colombier 	String *cmd;
2823e12c5d1SDavid du Colombier 	process *pp;
283bd389b36SDavid du Colombier 	int status, none;
2843e12c5d1SDavid du Colombier 	String *errstring=s_new();
2853e12c5d1SDavid du Colombier 
286bd389b36SDavid du Colombier 	none = dp->status == d_pipeto;
2873e12c5d1SDavid du Colombier 	/*
2883e12c5d1SDavid du Colombier 	 *  collect the arguments
2893e12c5d1SDavid du Colombier 	 */
2903e12c5d1SDavid du Colombier 	file = s_new();
2913e12c5d1SDavid du Colombier 	abspath(s_to_c(dp->addr), MAILROOT, file);
2923e12c5d1SDavid du Colombier 	next = d_rm_same(&dp);
2933e12c5d1SDavid du Colombier 	if(xflg)
2943e12c5d1SDavid du Colombier 		cmd = s_new();
2953e12c5d1SDavid du Colombier 	else
2963e12c5d1SDavid du Colombier 		cmd = s_clone(s_restart(next->repl1));
2973e12c5d1SDavid du Colombier 	for(; next != 0; next = d_rm_same(&dp)){
2983e12c5d1SDavid du Colombier 		if(xflg){
2993e12c5d1SDavid du Colombier 			s_append(cmd, s_to_c(next->addr));
3003e12c5d1SDavid du Colombier 			s_append(cmd, "\n");
3013e12c5d1SDavid du Colombier 		} else {
3023e12c5d1SDavid du Colombier 			if (next->repl2 != 0) {
3033e12c5d1SDavid du Colombier 				s_append(cmd, " ");
3043e12c5d1SDavid du Colombier 				s_append(cmd, s_to_c(next->repl2));
3053e12c5d1SDavid du Colombier 			}
3063e12c5d1SDavid du Colombier 		}
3073e12c5d1SDavid du Colombier 		d_insert(&list, next);
3083e12c5d1SDavid du Colombier 	}
3093e12c5d1SDavid du Colombier 
3103e12c5d1SDavid du Colombier 	if (nflg) {
3113e12c5d1SDavid du Colombier 		if(xflg)
3123e12c5d1SDavid du Colombier 			print("%s", s_to_c(cmd));
3133e12c5d1SDavid du Colombier 		else
3143e12c5d1SDavid du Colombier 			print("%s\n", s_to_c(cmd));
3153e12c5d1SDavid du Colombier 		s_free(cmd);
3163e12c5d1SDavid du Colombier 		s_free(file);
3173e12c5d1SDavid du Colombier 		return 0;
3183e12c5d1SDavid du Colombier 	}
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	/*
3213e12c5d1SDavid du Colombier 	 *  run the process
3223e12c5d1SDavid du Colombier 	 */
323bd389b36SDavid du Colombier 	pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 1, none);
3243e12c5d1SDavid du Colombier 	if(pp==0 || pp->std[0]==0 || pp->std[2]==0)
3253e12c5d1SDavid du Colombier 		return refuse(list, mp, "out of processes, pipes, or memory", 0);
3263e12c5d1SDavid du Colombier 	m_print(mp, pp->std[0]->fp, thissys, 0);
3273e12c5d1SDavid du Colombier 	stream_free(pp->std[0]);
3283e12c5d1SDavid du Colombier 	pp->std[0] = 0;
3293e12c5d1SDavid du Colombier 	while(s_read_line(pp->std[2]->fp, errstring))
3303e12c5d1SDavid du Colombier 		;
3313e12c5d1SDavid du Colombier 	status = proc_wait(pp);
3323e12c5d1SDavid du Colombier 	proc_free(pp);
3333e12c5d1SDavid du Colombier 	s_free(cmd);
3343e12c5d1SDavid du Colombier 
3353e12c5d1SDavid du Colombier 	/*
3363e12c5d1SDavid du Colombier 	 *  return status
3373e12c5d1SDavid du Colombier 	 */
3383e12c5d1SDavid du Colombier 	if (status != 0)
3393e12c5d1SDavid du Colombier 		return refuse(list, mp, s_to_c(errstring), status);
3403e12c5d1SDavid du Colombier 	loglist(list, mp, "remote");
3413e12c5d1SDavid du Colombier 	return 0;
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3443e12c5d1SDavid du Colombier /* dispose of local addresses */
3453e12c5d1SDavid du Colombier static int
3463e12c5d1SDavid du Colombier cat_mail(dest *dp, message *mp)
3473e12c5d1SDavid du Colombier {
3483e12c5d1SDavid du Colombier 	Biobuf *fp;
3493e12c5d1SDavid du Colombier 	char *rcvr, *cp;
3503e12c5d1SDavid du Colombier 	Lock *l;
3513e12c5d1SDavid du Colombier 	String *tmp;
3523e12c5d1SDavid du Colombier 
3533e12c5d1SDavid du Colombier 	if (nflg) {
3543e12c5d1SDavid du Colombier 		if(!xflg)
3553e12c5d1SDavid du Colombier 			print("cat >> %s\n", s_to_c(dp->repl1));
3563e12c5d1SDavid du Colombier 		else
3573e12c5d1SDavid du Colombier 			print("%s\n", s_to_c(dp->addr));
3583e12c5d1SDavid du Colombier 		return 0;
3593e12c5d1SDavid du Colombier 	}
3603e12c5d1SDavid du Colombier 	l = lock(s_to_c(dp->repl1));
3613e12c5d1SDavid du Colombier 	if(l == 0)
3623e12c5d1SDavid du Colombier 		return refuse(dp, mp, "can't lock mail file", 0);
3633e12c5d1SDavid du Colombier 	fp = sysopen(s_to_c(dp->repl1), "cal", MBOXMODE);
3643e12c5d1SDavid du Colombier 	if (fp == 0){
3653e12c5d1SDavid du Colombier 		tmp = s_append(0, s_to_c(dp->repl1));
3663e12c5d1SDavid du Colombier 		s_append(tmp, ".tmp");
3673e12c5d1SDavid du Colombier 		fp = sysopen(s_to_c(tmp), "cal", MBOXMODE);
3683e12c5d1SDavid du Colombier 		if(fp == 0){
3693e12c5d1SDavid du Colombier 			unlock(l);
3703e12c5d1SDavid du Colombier 			return refuse(dp, mp, "mail file cannot be opened", 0);
3713e12c5d1SDavid du Colombier 		}
3723e12c5d1SDavid du Colombier 		syslog(0, "mail", "error: used %s", s_to_c(tmp));
3733e12c5d1SDavid du Colombier 		s_free(tmp);
3743e12c5d1SDavid du Colombier 	}
3753e12c5d1SDavid du Colombier 	if(m_print(mp, fp, (char *)0, 1) < 0
376*219b2ee8SDavid du Colombier 	|| Bprint(fp, "\n") < 0
3773e12c5d1SDavid du Colombier 	|| Bflush(fp) < 0){
3783e12c5d1SDavid du Colombier 		sysclose(fp);
3793e12c5d1SDavid du Colombier 		unlock(l);
3803e12c5d1SDavid du Colombier 		return refuse(dp, mp, "error writing mail file", 0);
3813e12c5d1SDavid du Colombier 	}
3823e12c5d1SDavid du Colombier 	sysclose(fp);
3833e12c5d1SDavid du Colombier 	unlock(l);
3843e12c5d1SDavid du Colombier 	rcvr = s_to_c(dp->addr);
3853e12c5d1SDavid du Colombier 	if(cp = strrchr(rcvr, '!'))
3863e12c5d1SDavid du Colombier 		rcvr = cp+1;
3873e12c5d1SDavid du Colombier 	logdelivery(dp, rcvr, mp);
3883e12c5d1SDavid du Colombier 	return 0;
3893e12c5d1SDavid du Colombier }
3903e12c5d1SDavid du Colombier 
3913e12c5d1SDavid du Colombier static void
3923e12c5d1SDavid du Colombier appaddr(String *sp, dest *dp)
3933e12c5d1SDavid du Colombier {
3943e12c5d1SDavid du Colombier 	dest *parent;
3953e12c5d1SDavid du Colombier 
3963e12c5d1SDavid du Colombier 	if (dp->parent != 0) {
3973e12c5d1SDavid du Colombier 		for(parent=dp->parent; parent->parent!=0; parent=parent->parent)
3983e12c5d1SDavid du Colombier 			;
3993e12c5d1SDavid du Colombier 		s_append(sp, s_to_c(parent->addr));
4003e12c5d1SDavid du Colombier 		s_append(sp, "' alias `");
4013e12c5d1SDavid du Colombier 	}
4023e12c5d1SDavid du Colombier 	s_append(sp, s_to_c(dp->addr));
4033e12c5d1SDavid du Colombier }
4043e12c5d1SDavid du Colombier 
4053e12c5d1SDavid du Colombier /* reject delivery */
4063e12c5d1SDavid du Colombier static int
4073e12c5d1SDavid du Colombier refuse(dest *list, message *mp, char *cp, int status)
4083e12c5d1SDavid du Colombier {
4093e12c5d1SDavid du Colombier 	String *errstring=s_new();
4103e12c5d1SDavid du Colombier 	dest *dp;
4113e12c5d1SDavid du Colombier 	int rv;
4123e12c5d1SDavid du Colombier 
4133e12c5d1SDavid du Colombier 	dp = d_rm(&list);
4143e12c5d1SDavid du Colombier 	mkerrstring(errstring, mp, dp, list, cp, status);
415*219b2ee8SDavid du Colombier 
4163e12c5d1SDavid du Colombier 	/*
4173e12c5d1SDavid du Colombier 	 * if on a tty just report the error.  Otherwise send mail
4183e12c5d1SDavid du Colombier 	 * reporting the error.  N.B. To avoid mail loops, don't
4193e12c5d1SDavid du Colombier 	 * send mail reporting a failure of mail to reach the postmaster.
4203e12c5d1SDavid du Colombier 	 */
421*219b2ee8SDavid du Colombier 	if (!rmail) {
4223e12c5d1SDavid du Colombier 		fprint(2, "%s\n", s_to_c(errstring));
4233e12c5d1SDavid du Colombier 		savemail = 1;
4243e12c5d1SDavid du Colombier 		rv = 1;
4253e12c5d1SDavid du Colombier 	} else {
4263e12c5d1SDavid du Colombier 		if (strcmp(s_to_c(mp->replyaddr), "postmaster")!=0)
4273e12c5d1SDavid du Colombier 			rv = replymsg(errstring, mp, dp);
4283e12c5d1SDavid du Colombier 		else
4293e12c5d1SDavid du Colombier 			rv = 1;
4303e12c5d1SDavid du Colombier 	}
4313e12c5d1SDavid du Colombier 	logrefusal(dp, mp, s_to_c(errstring));
4323e12c5d1SDavid du Colombier 	s_free(errstring);
4333e12c5d1SDavid du Colombier 	return rv;
4343e12c5d1SDavid du Colombier }
4353e12c5d1SDavid du Colombier 
4363e12c5d1SDavid du Colombier /* make the error message */
4373e12c5d1SDavid du Colombier static void
4383e12c5d1SDavid du Colombier mkerrstring(String *errstring, message *mp, dest *dp, dest *list, char *cp, int status)
4393e12c5d1SDavid du Colombier {
4403e12c5d1SDavid du Colombier 	dest *next;
4413e12c5d1SDavid du Colombier 	char smsg[64];
4423e12c5d1SDavid du Colombier 
4433e12c5d1SDavid du Colombier 	/* list all aliases */
4443e12c5d1SDavid du Colombier 	s_append(errstring, "Mail to `");
4453e12c5d1SDavid du Colombier 	appaddr(errstring, dp);
4463e12c5d1SDavid du Colombier 	for(next = d_rm(&list); next != 0; next = d_rm(&list)) {
4473e12c5d1SDavid du Colombier 		s_append(errstring, "', '");
4483e12c5d1SDavid du Colombier 		appaddr(errstring, next);
4493e12c5d1SDavid du Colombier 		d_insert(&dp, next);
4503e12c5d1SDavid du Colombier 	}
4513e12c5d1SDavid du Colombier 	s_append(errstring, "' from '");
4523e12c5d1SDavid du Colombier 	s_append(errstring, s_to_c(mp->sender));
4533e12c5d1SDavid du Colombier 	s_append(errstring, "' failed.\n");
4543e12c5d1SDavid du Colombier 
4553e12c5d1SDavid du Colombier 	/* >> and | deserve different flavored messages */
4563e12c5d1SDavid du Colombier 	switch(dp->status) {
4573e12c5d1SDavid du Colombier 	case d_pipe:
4583e12c5d1SDavid du Colombier 		s_append(errstring, "The mailer `");
4593e12c5d1SDavid du Colombier 		s_append(errstring, s_to_c(dp->repl1));
4603e12c5d1SDavid du Colombier 		sprint(smsg, "' returned error status %x.\n", status);
4613e12c5d1SDavid du Colombier 		s_append(errstring, smsg);
4623e12c5d1SDavid du Colombier 		s_append(errstring, "The error message was:\n");
4633e12c5d1SDavid du Colombier 		s_append(errstring, cp);
4643e12c5d1SDavid du Colombier 		break;
4653e12c5d1SDavid du Colombier 	default:
4663e12c5d1SDavid du Colombier 		s_append(errstring, "The error message was:\n");
4673e12c5d1SDavid du Colombier 		s_append(errstring, cp);
4683e12c5d1SDavid du Colombier 		break;
4693e12c5d1SDavid du Colombier 	}
4703e12c5d1SDavid du Colombier }
4713e12c5d1SDavid du Colombier 
4723e12c5d1SDavid du Colombier /*
4733e12c5d1SDavid du Colombier  *  reply with up to 1024 characters of the
4743e12c5d1SDavid du Colombier  *  original message
4753e12c5d1SDavid du Colombier  */
4763e12c5d1SDavid du Colombier static int
4773e12c5d1SDavid du Colombier replymsg(String *errstring, message *mp, dest *dp)
4783e12c5d1SDavid du Colombier {
4793e12c5d1SDavid du Colombier 	message *refp = m_new();
4803e12c5d1SDavid du Colombier 	dest *ndp;
4813e12c5d1SDavid du Colombier 	char *rcvr;
4823e12c5d1SDavid du Colombier 	int rv;
4833e12c5d1SDavid du Colombier 
4843e12c5d1SDavid du Colombier 	rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr);
4853e12c5d1SDavid du Colombier 	ndp = d_new(s_copy(rcvr));
4863e12c5d1SDavid du Colombier 	s_append(refp->sender, "postmaster");
4873e12c5d1SDavid du Colombier 	s_append(refp->replyaddr, "postmaster");
4883e12c5d1SDavid du Colombier 	s_append(refp->date, thedate());
4893e12c5d1SDavid du Colombier 	s_append(refp->body, s_to_c(errstring));
4903e12c5d1SDavid du Colombier 	s_append(refp->body, "\nThe message began:\n");
4913e12c5d1SDavid du Colombier 	s_nappend(refp->body, s_to_c(mp->body), 8*1024);
4923e12c5d1SDavid du Colombier 	refp->size = strlen(s_to_c(refp->body));
4933e12c5d1SDavid du Colombier 	rv = send(ndp, refp, 0);
4943e12c5d1SDavid du Colombier 	m_free(refp);
4953e12c5d1SDavid du Colombier 	d_free(ndp);
4963e12c5d1SDavid du Colombier 	return rv;
4973e12c5d1SDavid du Colombier }
498