xref: /plan9/sys/src/cmd/upas/send/main.c (revision ad8ef9344eb71318231fca588e45b81b27f8637d)
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;
6219b2ee8SDavid 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;
117dd7cddfSDavid du Colombier int iflg = 1;
127dd7cddfSDavid du Colombier int nosummary;
133e12c5d1SDavid du Colombier 
143e12c5d1SDavid du Colombier /* global to this file */
153e12c5d1SDavid du Colombier static String *errstring;
163e12c5d1SDavid du Colombier static message *mp;
173e12c5d1SDavid du Colombier static int interrupt;
183e12c5d1SDavid du Colombier static int savemail;
193e12c5d1SDavid du Colombier static Biobuf in;
207dd7cddfSDavid du Colombier static int forked;
217dd7cddfSDavid du Colombier static int add822headers = 1;
227dd7cddfSDavid du Colombier static String *arglist;
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier /* predeclared */
253e12c5d1SDavid du Colombier static int	send(dest *, message *, int);
263e12c5d1SDavid du Colombier static void	lesstedious(void);
273e12c5d1SDavid du Colombier static void	save_mail(message *);
283e12c5d1SDavid du Colombier static int	complain_mail(dest *, message *);
293e12c5d1SDavid du Colombier static int	pipe_mail(dest *, message *);
303e12c5d1SDavid du Colombier static void	appaddr(String *, dest *);
313e12c5d1SDavid du Colombier static void	mkerrstring(String *, message *, dest *, dest *, char *, int);
323e12c5d1SDavid du Colombier static int	replymsg(String *, message *, dest *);
337dd7cddfSDavid du Colombier static int	catchint(void*, char*);
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier void
usage(void)367dd7cddfSDavid du Colombier usage(void)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier 	fprint(2, "usage: mail [-birtx] list-of-addresses\n");
397dd7cddfSDavid du Colombier 	exits("usage");
407dd7cddfSDavid du Colombier }
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier void
main(int argc,char * argv[])433e12c5d1SDavid du Colombier main(int argc, char *argv[])
443e12c5d1SDavid du Colombier {
453e12c5d1SDavid du Colombier 	dest *dp=0;
463e12c5d1SDavid du Colombier 	int checkforward;
473e12c5d1SDavid du Colombier 	char *base;
487dd7cddfSDavid du Colombier 	int rv;
49219b2ee8SDavid du Colombier 
503e12c5d1SDavid du Colombier 	/* process args */
513e12c5d1SDavid du Colombier 	ARGBEGIN{
523e12c5d1SDavid du Colombier 	case '#':
533e12c5d1SDavid du Colombier 		nflg = 1;
543e12c5d1SDavid du Colombier 		break;
557dd7cddfSDavid du Colombier 	case 'b':
567dd7cddfSDavid du Colombier 		add822headers = 0;
577dd7cddfSDavid du Colombier 		break;
583e12c5d1SDavid du Colombier 	case 'x':
593e12c5d1SDavid du Colombier 		nflg = 1;
603e12c5d1SDavid du Colombier 		xflg = 1;
613e12c5d1SDavid du Colombier 		break;
623e12c5d1SDavid du Colombier 	case 'd':
633e12c5d1SDavid du Colombier 		debug = 1;
643e12c5d1SDavid du Colombier 		break;
657dd7cddfSDavid du Colombier 	case 'i':
667dd7cddfSDavid du Colombier 		iflg = 0;
677dd7cddfSDavid du Colombier 		break;
683e12c5d1SDavid du Colombier 	case 'r':
693e12c5d1SDavid du Colombier 		rflg = 1;
703e12c5d1SDavid du Colombier 		break;
713e12c5d1SDavid du Colombier 	default:
727dd7cddfSDavid du Colombier 		usage();
733e12c5d1SDavid du Colombier 	}ARGEND
743e12c5d1SDavid du Colombier 
757dd7cddfSDavid du Colombier 	while(*argv){
767dd7cddfSDavid du Colombier 		if(shellchars(*argv)){
777dd7cddfSDavid du Colombier 			fprint(2, "illegal characters in destination\n");
787dd7cddfSDavid du Colombier 			exits("syntax");
793e12c5d1SDavid du Colombier 		}
807dd7cddfSDavid du Colombier 		d_insert(&dp, d_new(s_copy(*argv++)));
817dd7cddfSDavid du Colombier 	}
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	if (dp == 0)
847dd7cddfSDavid du Colombier 		usage();
857dd7cddfSDavid du Colombier 	arglist = d_to(dp);
863e12c5d1SDavid du Colombier 
873e12c5d1SDavid du Colombier 	/*
883e12c5d1SDavid du Colombier 	 * get context:
893e12c5d1SDavid du Colombier 	 *	- whether we're rmail or mail
903e12c5d1SDavid du Colombier 	 */
913e12c5d1SDavid du Colombier 	base = basename(argv0);
923e12c5d1SDavid du Colombier 	checkforward = rmail = (strcmp(base, "rmail")==0) | rflg;
933e12c5d1SDavid du Colombier 	thissys = sysname_read();
94219b2ee8SDavid du Colombier 	altthissys = alt_sysname_read();
957dd7cddfSDavid du Colombier 	if(rmail)
967dd7cddfSDavid du Colombier 		add822headers = 0;
973e12c5d1SDavid du Colombier 
983e12c5d1SDavid du Colombier 	/*
993e12c5d1SDavid du Colombier 	 *  read the mail.  If an interrupt occurs while reading, save in
1003e12c5d1SDavid du Colombier 	 *  dead.letter
1013e12c5d1SDavid du Colombier 	 */
1023e12c5d1SDavid du Colombier 	if (!nflg) {
1033e12c5d1SDavid du Colombier 		Binit(&in, 0, OREAD);
1047dd7cddfSDavid du Colombier 		if(!rmail)
1057dd7cddfSDavid du Colombier 			atnotify(catchint, 1);
1067dd7cddfSDavid du Colombier 		mp = m_read(&in, rmail, !iflg);
1073e12c5d1SDavid du Colombier 		if (mp == 0)
1083e12c5d1SDavid du Colombier 			exit(0);
1093e12c5d1SDavid du Colombier 		if (interrupt != 0) {
1103e12c5d1SDavid du Colombier 			save_mail(mp);
1113e12c5d1SDavid du Colombier 			exit(1);
1123e12c5d1SDavid du Colombier 		}
1133e12c5d1SDavid du Colombier 	} else {
1143e12c5d1SDavid du Colombier 		mp = m_new();
1157dd7cddfSDavid du Colombier 		if(default_from(mp) < 0){
1167dd7cddfSDavid du Colombier 			fprint(2, "%s: can't determine login name\n", argv0);
1177dd7cddfSDavid du Colombier 			exit(1);
1187dd7cddfSDavid du Colombier 		}
1193e12c5d1SDavid du Colombier 	}
1203e12c5d1SDavid du Colombier 	errstring = s_new();
1213e12c5d1SDavid du Colombier 	getrules();
1223e12c5d1SDavid du Colombier 
1233e12c5d1SDavid du Colombier 	/*
1243e12c5d1SDavid du Colombier 	 *  If this is a gateway, translate the sender address into a local
1253e12c5d1SDavid du Colombier 	 *  address.  This only happens if mail to the local address is
1263e12c5d1SDavid du Colombier 	 *  forwarded to the sender.
1273e12c5d1SDavid du Colombier 	 */
1283e12c5d1SDavid du Colombier 	gateway(mp);
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	/*
1313e12c5d1SDavid du Colombier 	 *  Protect against shell characters in the sender name for
1323e12c5d1SDavid du Colombier 	 *  security reasons.
1333e12c5d1SDavid du Colombier 	 */
1347dd7cddfSDavid du Colombier 	mp->sender = escapespecial(mp->sender);
1353e12c5d1SDavid du Colombier 	if (shellchars(s_to_c(mp->sender)))
1363e12c5d1SDavid du Colombier 		mp->replyaddr = s_copy("postmaster");
1373e12c5d1SDavid du Colombier 	else
1383e12c5d1SDavid du Colombier 		mp->replyaddr = s_clone(mp->sender);
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 	/*
1417dd7cddfSDavid du Colombier 	 *  reject messages that have been looping for too long
1427dd7cddfSDavid du Colombier 	 */
1437dd7cddfSDavid du Colombier 	if(mp->received > 32)
1447dd7cddfSDavid du Colombier 		exit(refuse(dp, mp, "possible forward loop", 0, 0));
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier 	/*
1473e12c5d1SDavid du Colombier 	 *  reject messages that are too long.  We don't do it earlier
1483e12c5d1SDavid du Colombier 	 *  in m_read since we haven't set up enough things yet.
1493e12c5d1SDavid du Colombier 	 */
1503e12c5d1SDavid du Colombier 	if(mp->size < 0)
1517dd7cddfSDavid du Colombier 		exit(refuse(dp, mp, "message too long", 0, 0));
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 	rv = send(dp, mp, checkforward);
1543e12c5d1SDavid du Colombier 	if(savemail)
1553e12c5d1SDavid du Colombier 		save_mail(mp);
1563e12c5d1SDavid du Colombier 	if(mp)
1573e12c5d1SDavid du Colombier 		m_free(mp);
1583e12c5d1SDavid du Colombier 	exit(rv);
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier 
1613e12c5d1SDavid du Colombier /* send a message to a list of sites */
1623e12c5d1SDavid du Colombier static int
send(dest * destp,message * mp,int checkforward)1633e12c5d1SDavid du Colombier send(dest *destp, message *mp, int checkforward)
1643e12c5d1SDavid du Colombier {
1653e12c5d1SDavid du Colombier 	dest *dp;		/* destination being acted upon */
1663e12c5d1SDavid du Colombier 	dest *bound;		/* bound destinations */
1673e12c5d1SDavid du Colombier 	int errors=0;
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier 	/* bind the destinations to actions */
1703e12c5d1SDavid du Colombier 	bound = up_bind(destp, mp, checkforward);
1717dd7cddfSDavid du Colombier 	if(add822headers && mp->haveto == 0){
1727dd7cddfSDavid du Colombier 		if(nosummary)
1737dd7cddfSDavid du Colombier 			mp->to = d_to(bound);
1747dd7cddfSDavid du Colombier 		else
1757dd7cddfSDavid du Colombier 			mp->to = arglist;
1767dd7cddfSDavid du Colombier 	}
1773e12c5d1SDavid du Colombier 
1783e12c5d1SDavid du Colombier 	/* loop through and execute commands */
1793e12c5d1SDavid du Colombier 	for (dp = d_rm(&bound); dp != 0; dp = d_rm(&bound)) {
1803e12c5d1SDavid du Colombier 		switch (dp->status) {
1813e12c5d1SDavid du Colombier 		case d_cat:
1823e12c5d1SDavid du Colombier 			errors += cat_mail(dp, mp);
1833e12c5d1SDavid du Colombier 			break;
1843e12c5d1SDavid du Colombier 		case d_pipeto:
1853e12c5d1SDavid du Colombier 		case d_pipe:
1863e12c5d1SDavid du Colombier 			if (!rmail && !nflg && !forked) {
1873e12c5d1SDavid du Colombier 				forked = 1;
1883e12c5d1SDavid du Colombier 				lesstedious();
1893e12c5d1SDavid du Colombier 			}
1903e12c5d1SDavid du Colombier 			errors += pipe_mail(dp, mp);
1913e12c5d1SDavid du Colombier 			break;
1923e12c5d1SDavid du Colombier 		default:
1933e12c5d1SDavid du Colombier 			errors += complain_mail(dp, mp);
1943e12c5d1SDavid du Colombier 			break;
1953e12c5d1SDavid du Colombier 		}
1963e12c5d1SDavid du Colombier 	}
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier 	return errors;
1993e12c5d1SDavid du Colombier }
2003e12c5d1SDavid du Colombier 
2013e12c5d1SDavid du Colombier /* avoid user tedium (as Mike Lesk said in a previous version) */
2023e12c5d1SDavid du Colombier static void
lesstedious(void)2033e12c5d1SDavid du Colombier lesstedious(void)
2043e12c5d1SDavid du Colombier {
2053e12c5d1SDavid du Colombier 	int i;
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier 	if(debug)
2083e12c5d1SDavid du Colombier 		return;
209219b2ee8SDavid du Colombier 
2103e12c5d1SDavid du Colombier 	switch(fork()){
2113e12c5d1SDavid du Colombier 	case -1:
2123e12c5d1SDavid du Colombier 		break;
2133e12c5d1SDavid du Colombier 	case 0:
2147dd7cddfSDavid du Colombier 		sysdetach();
2157dd7cddfSDavid du Colombier 		for(i=0; i<3; i++)
2163e12c5d1SDavid du Colombier 			close(i);
2173e12c5d1SDavid du Colombier 		savemail = 0;
2183e12c5d1SDavid du Colombier 		break;
2193e12c5d1SDavid du Colombier 	default:
2203e12c5d1SDavid du Colombier 		exit(0);
2213e12c5d1SDavid du Colombier 	}
2223e12c5d1SDavid du Colombier }
2233e12c5d1SDavid du Colombier 
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier /* save the mail */
2263e12c5d1SDavid du Colombier static void
save_mail(message * mp)2273e12c5d1SDavid du Colombier save_mail(message *mp)
2283e12c5d1SDavid du Colombier {
2293e12c5d1SDavid du Colombier 	Biobuf *fp;
2303e12c5d1SDavid du Colombier 	String *file;
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier 	file = s_new();
2337dd7cddfSDavid du Colombier 	deadletter(file);
2347dd7cddfSDavid du Colombier 	fp = sysopen(s_to_c(file), "cAt", 0660);
2357dd7cddfSDavid du Colombier 	if (fp == 0)
2363e12c5d1SDavid du Colombier 		return;
2373e12c5d1SDavid du Colombier 	m_bprint(mp, fp);
2383e12c5d1SDavid du Colombier 	sysclose(fp);
2393e12c5d1SDavid du Colombier 	fprint(2, "saved in %s\n", s_to_c(file));
2403e12c5d1SDavid du Colombier 	s_free(file);
2413e12c5d1SDavid du Colombier }
2423e12c5d1SDavid du Colombier 
2433e12c5d1SDavid du Colombier /* remember the interrupt happened */
2447dd7cddfSDavid du Colombier 
2457dd7cddfSDavid du Colombier static int
catchint(void * a,char * msg)2467dd7cddfSDavid du Colombier catchint(void *a, char *msg)
2477dd7cddfSDavid du Colombier {
2487dd7cddfSDavid du Colombier 	USED(a);
2497dd7cddfSDavid du Colombier 	if(strstr(msg, "interrupt") || strstr(msg, "hangup")) {
2507dd7cddfSDavid du Colombier 		interrupt = 1;
2517dd7cddfSDavid du Colombier 		return 1;
2527dd7cddfSDavid du Colombier 	}
2537dd7cddfSDavid du Colombier 	return 0;
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier 
2563e12c5d1SDavid du Colombier /* dispose of incorrect addresses */
2573e12c5d1SDavid du Colombier static int
complain_mail(dest * dp,message * mp)2583e12c5d1SDavid du Colombier complain_mail(dest *dp, message *mp)
2593e12c5d1SDavid du Colombier {
2603e12c5d1SDavid du Colombier 	char *msg;
2613e12c5d1SDavid du Colombier 
2623e12c5d1SDavid du Colombier 	switch (dp->status) {
2633e12c5d1SDavid du Colombier 	case d_undefined:
2643e12c5d1SDavid du Colombier 		msg = "Invalid address"; /* a little different, for debugging */
2653e12c5d1SDavid du Colombier 		break;
2663e12c5d1SDavid du Colombier 	case d_syntax:
2673e12c5d1SDavid du Colombier 		msg = "invalid address";
2683e12c5d1SDavid du Colombier 		break;
2693e12c5d1SDavid du Colombier 	case d_unknown:
2703e12c5d1SDavid du Colombier 		msg = "unknown user";
2713e12c5d1SDavid du Colombier 		break;
2723e12c5d1SDavid du Colombier 	case d_eloop:
2733e12c5d1SDavid du Colombier 	case d_loop:
2743e12c5d1SDavid du Colombier 		msg = "forwarding loop";
2753e12c5d1SDavid du Colombier 		break;
2763e12c5d1SDavid du Colombier 	case d_noforward:
2773e12c5d1SDavid du Colombier 		if(dp->pstat && *s_to_c(dp->repl2))
2787dd7cddfSDavid du Colombier 			return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat, 0);
2793e12c5d1SDavid du Colombier 		else
2803e12c5d1SDavid du Colombier 			msg = "destination unknown or forwarding disallowed";
2813e12c5d1SDavid du Colombier 		break;
2823e12c5d1SDavid du Colombier 	case d_pipe:
2833e12c5d1SDavid du Colombier 		msg = "broken pipe";
2843e12c5d1SDavid du Colombier 		break;
2853e12c5d1SDavid du Colombier 	case d_cat:
2863e12c5d1SDavid du Colombier 		msg = "broken cat";
2873e12c5d1SDavid du Colombier 		break;
2883e12c5d1SDavid du Colombier 	case d_translate:
2893e12c5d1SDavid du Colombier 		if(dp->pstat && *s_to_c(dp->repl2))
2907dd7cddfSDavid du Colombier 			return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat, 0);
2913e12c5d1SDavid du Colombier 		else
2923e12c5d1SDavid du Colombier 			msg = "name translation failed";
2933e12c5d1SDavid du Colombier 		break;
2943e12c5d1SDavid du Colombier 	case d_alias:
2953e12c5d1SDavid du Colombier 		msg = "broken alias";
2963e12c5d1SDavid du Colombier 		break;
2973e12c5d1SDavid du Colombier 	case d_badmbox:
2983e12c5d1SDavid du Colombier 		msg = "corrupted mailbox";
2993e12c5d1SDavid du Colombier 		break;
3003e12c5d1SDavid du Colombier 	case d_resource:
3017dd7cddfSDavid du Colombier 		return refuse(dp, mp, "out of some resource.  Try again later.", 0, 1);
3023e12c5d1SDavid du Colombier 	default:
3033e12c5d1SDavid du Colombier 		msg = "unknown d_";
3043e12c5d1SDavid du Colombier 		break;
3053e12c5d1SDavid du Colombier 	}
3063e12c5d1SDavid du Colombier 	if (nflg) {
3073e12c5d1SDavid du Colombier 		print("%s: %s\n", msg, s_to_c(dp->addr));
3083e12c5d1SDavid du Colombier 		return 0;
3093e12c5d1SDavid du Colombier 	}
3107dd7cddfSDavid du Colombier 	return refuse(dp, mp, msg, 0, 0);
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier 
3133e12c5d1SDavid du Colombier /* dispose of remote addresses */
3143e12c5d1SDavid du Colombier static int
pipe_mail(dest * dp,message * mp)3153e12c5d1SDavid du Colombier pipe_mail(dest *dp, message *mp)
3163e12c5d1SDavid du Colombier {
3173e12c5d1SDavid du Colombier 	dest *next, *list=0;
3183e12c5d1SDavid du Colombier 	String *cmd;
3193e12c5d1SDavid du Colombier 	process *pp;
320*ad8ef934SDavid du Colombier 	int status, r;
3217dd7cddfSDavid du Colombier 	char *none;
3223e12c5d1SDavid du Colombier 	String *errstring=s_new();
3233e12c5d1SDavid du Colombier 
3247dd7cddfSDavid du Colombier 	if (dp->status == d_pipeto)
3257dd7cddfSDavid du Colombier 		none = "none";
3267dd7cddfSDavid du Colombier 	else
3277dd7cddfSDavid du Colombier 		none = 0;
3283e12c5d1SDavid du Colombier 	/*
3293e12c5d1SDavid du Colombier 	 *  collect the arguments
3303e12c5d1SDavid du Colombier 	 */
3313e12c5d1SDavid du Colombier 	next = d_rm_same(&dp);
3323e12c5d1SDavid du Colombier 	if(xflg)
3333e12c5d1SDavid du Colombier 		cmd = s_new();
3343e12c5d1SDavid du Colombier 	else
3357dd7cddfSDavid du Colombier 		cmd = s_clone(next->repl1);
3363e12c5d1SDavid du Colombier 	for(; next != 0; next = d_rm_same(&dp)){
3373e12c5d1SDavid du Colombier 		if(xflg){
3383e12c5d1SDavid du Colombier 			s_append(cmd, s_to_c(next->addr));
3393e12c5d1SDavid du Colombier 			s_append(cmd, "\n");
3403e12c5d1SDavid du Colombier 		} else {
3413e12c5d1SDavid du Colombier 			if (next->repl2 != 0) {
3423e12c5d1SDavid du Colombier 				s_append(cmd, " ");
3433e12c5d1SDavid du Colombier 				s_append(cmd, s_to_c(next->repl2));
3443e12c5d1SDavid du Colombier 			}
3453e12c5d1SDavid du Colombier 		}
3463e12c5d1SDavid du Colombier 		d_insert(&list, next);
3473e12c5d1SDavid du Colombier 	}
3483e12c5d1SDavid du Colombier 
3493e12c5d1SDavid du Colombier 	if (nflg) {
3503e12c5d1SDavid du Colombier 		if(xflg)
3513e12c5d1SDavid du Colombier 			print("%s", s_to_c(cmd));
3523e12c5d1SDavid du Colombier 		else
3533e12c5d1SDavid du Colombier 			print("%s\n", s_to_c(cmd));
3543e12c5d1SDavid du Colombier 		s_free(cmd);
3553e12c5d1SDavid du Colombier 		return 0;
3563e12c5d1SDavid du Colombier 	}
3573e12c5d1SDavid du Colombier 
3583e12c5d1SDavid du Colombier 	/*
3593e12c5d1SDavid du Colombier 	 *  run the process
3603e12c5d1SDavid du Colombier 	 */
361bd389b36SDavid du Colombier 	pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 1, none);
3623e12c5d1SDavid du Colombier 	if(pp==0 || pp->std[0]==0 || pp->std[2]==0)
3637dd7cddfSDavid du Colombier 		return refuse(list, mp, "out of processes, pipes, or memory", 0, 1);
3647dd7cddfSDavid du Colombier 	pipesig(0);
3653e12c5d1SDavid du Colombier 	m_print(mp, pp->std[0]->fp, thissys, 0);
3667dd7cddfSDavid du Colombier 	pipesigoff();
3673e12c5d1SDavid du Colombier 	stream_free(pp->std[0]);
3683e12c5d1SDavid du Colombier 	pp->std[0] = 0;
3693e12c5d1SDavid du Colombier 	while(s_read_line(pp->std[2]->fp, errstring))
3703e12c5d1SDavid du Colombier 		;
3713e12c5d1SDavid du Colombier 	status = proc_wait(pp);
3723e12c5d1SDavid du Colombier 	proc_free(pp);
3733e12c5d1SDavid du Colombier 	s_free(cmd);
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier 	/*
3763e12c5d1SDavid du Colombier 	 *  return status
3773e12c5d1SDavid du Colombier 	 */
378*ad8ef934SDavid du Colombier 	if (status != 0) {
379*ad8ef934SDavid du Colombier 		r = refuse(list, mp, s_to_c(errstring), status, 0);
380*ad8ef934SDavid du Colombier 		s_free(errstring);
381*ad8ef934SDavid du Colombier 		return r;
382*ad8ef934SDavid du Colombier 	}
383*ad8ef934SDavid du Colombier 	s_free(errstring);
3843e12c5d1SDavid du Colombier 	loglist(list, mp, "remote");
3853e12c5d1SDavid du Colombier 	return 0;
3863e12c5d1SDavid du Colombier }
3873e12c5d1SDavid du Colombier 
3883e12c5d1SDavid du Colombier static void
appaddr(String * sp,dest * dp)3893e12c5d1SDavid du Colombier appaddr(String *sp, dest *dp)
3903e12c5d1SDavid du Colombier {
3913e12c5d1SDavid du Colombier 	dest *parent;
3927dd7cddfSDavid du Colombier 	String *s;
3933e12c5d1SDavid du Colombier 
3943e12c5d1SDavid du Colombier 	if (dp->parent != 0) {
3953e12c5d1SDavid du Colombier 		for(parent=dp->parent; parent->parent!=0; parent=parent->parent)
3963e12c5d1SDavid du Colombier 			;
3977dd7cddfSDavid du Colombier 		s = unescapespecial(s_clone(parent->addr));
3987dd7cddfSDavid du Colombier 		s_append(sp, s_to_c(s));
3997dd7cddfSDavid du Colombier 		s_free(s);
4003e12c5d1SDavid du Colombier 		s_append(sp, "' alias `");
4013e12c5d1SDavid du Colombier 	}
4027dd7cddfSDavid du Colombier 	s = unescapespecial(s_clone(dp->addr));
4037dd7cddfSDavid du Colombier 	s_append(sp, s_to_c(s));
4047dd7cddfSDavid du Colombier 	s_free(s);
4053e12c5d1SDavid du Colombier }
4063e12c5d1SDavid du Colombier 
4077dd7cddfSDavid du Colombier /*
4087dd7cddfSDavid du Colombier  *  reject delivery
4097dd7cddfSDavid du Colombier  *
4107dd7cddfSDavid du Colombier  *  returns	0	- if mail has been disposed of
4117dd7cddfSDavid du Colombier  *		other	- if mail has not been disposed
4127dd7cddfSDavid du Colombier  */
4139a747e4fSDavid du Colombier int
refuse(dest * list,message * mp,char * cp,int status,int outofresources)4147dd7cddfSDavid du Colombier refuse(dest *list, message *mp, char *cp, int status, int outofresources)
4153e12c5d1SDavid du Colombier {
4163e12c5d1SDavid du Colombier 	String *errstring=s_new();
4173e12c5d1SDavid du Colombier 	dest *dp;
4183e12c5d1SDavid du Colombier 	int rv;
4193e12c5d1SDavid du Colombier 
4203e12c5d1SDavid du Colombier 	dp = d_rm(&list);
4213e12c5d1SDavid du Colombier 	mkerrstring(errstring, mp, dp, list, cp, status);
422219b2ee8SDavid du Colombier 
4233e12c5d1SDavid du Colombier 	/*
4247dd7cddfSDavid du Colombier 	 *  log first in case we get into trouble
4253e12c5d1SDavid du Colombier 	 */
4267dd7cddfSDavid du Colombier 	logrefusal(dp, mp, s_to_c(errstring));
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 	/*
4297dd7cddfSDavid du Colombier 	 *  bulk mail is never replied to, if we're out of resources,
4307dd7cddfSDavid du Colombier 	 *  let the sender try again
4317dd7cddfSDavid du Colombier 	 */
4327dd7cddfSDavid du Colombier 	if(rmail){
4337dd7cddfSDavid du Colombier 		/* accept it or request a retry */
4347dd7cddfSDavid du Colombier 		if(outofresources){
435d9306527SDavid du Colombier 			fprint(2, "Mail %s\n", s_to_c(errstring));
4367dd7cddfSDavid du Colombier 			rv = 1;					/* try again later */
4377dd7cddfSDavid du Colombier 		} else if(mp->bulk)
4387dd7cddfSDavid du Colombier 			rv = 0;					/* silently discard bulk */
4397dd7cddfSDavid du Colombier 		else
4407dd7cddfSDavid du Colombier 			rv = replymsg(errstring, mp, dp);	/* try later if we can't reply */
4417dd7cddfSDavid du Colombier 	} else {
4427dd7cddfSDavid du Colombier 		/* aysnchronous delivery only happens if !rmail */
4437dd7cddfSDavid du Colombier 		if(forked){
4447dd7cddfSDavid du Colombier 			/*
4457dd7cddfSDavid du Colombier 			 *  if spun off for asynchronous delivery, we own the mail now.
4467dd7cddfSDavid du Colombier 			 *  return it or dump it on the floor.  rv really doesn't matter.
4477dd7cddfSDavid du Colombier 			 */
4487dd7cddfSDavid du Colombier 			rv = 0;
4497dd7cddfSDavid du Colombier 			if(!outofresources && !mp->bulk)
4507dd7cddfSDavid du Colombier 				replymsg(errstring, mp, dp);
4517dd7cddfSDavid du Colombier 		} else {
452d9306527SDavid du Colombier 			fprint(2, "Mail %s\n", s_to_c(errstring));
4533e12c5d1SDavid du Colombier 			savemail = 1;
4543e12c5d1SDavid du Colombier 			rv = 1;
4553e12c5d1SDavid du Colombier 		}
4567dd7cddfSDavid du Colombier 	}
4577dd7cddfSDavid du Colombier 
4583e12c5d1SDavid du Colombier 	s_free(errstring);
4593e12c5d1SDavid du Colombier 	return rv;
4603e12c5d1SDavid du Colombier }
4613e12c5d1SDavid du Colombier 
4623e12c5d1SDavid du Colombier /* make the error message */
4633e12c5d1SDavid du Colombier static void
mkerrstring(String * errstring,message * mp,dest * dp,dest * list,char * cp,int status)4643e12c5d1SDavid du Colombier mkerrstring(String *errstring, message *mp, dest *dp, dest *list, char *cp, int status)
4653e12c5d1SDavid du Colombier {
4663e12c5d1SDavid du Colombier 	dest *next;
4673e12c5d1SDavid du Colombier 	char smsg[64];
4687dd7cddfSDavid du Colombier 	String *sender;
4697dd7cddfSDavid du Colombier 
4707dd7cddfSDavid du Colombier 	sender = unescapespecial(s_clone(mp->sender));
4713e12c5d1SDavid du Colombier 
4723e12c5d1SDavid du Colombier 	/* list all aliases */
473d9306527SDavid du Colombier 	s_append(errstring, " from '");
474d9306527SDavid du Colombier 	s_append(errstring, s_to_c(sender));
475d9306527SDavid du Colombier 	s_append(errstring, "'\nto '");
4763e12c5d1SDavid du Colombier 	appaddr(errstring, dp);
4773e12c5d1SDavid du Colombier 	for(next = d_rm(&list); next != 0; next = d_rm(&list)) {
478d9306527SDavid du Colombier 		s_append(errstring, "'\nand '");
4793e12c5d1SDavid du Colombier 		appaddr(errstring, next);
4803e12c5d1SDavid du Colombier 		d_insert(&dp, next);
4813e12c5d1SDavid du Colombier 	}
482d9306527SDavid du Colombier 	s_append(errstring, "'\nfailed with error '");
483d9306527SDavid du Colombier 	s_append(errstring, cp);
484d9306527SDavid du Colombier 	s_append(errstring, "'.\n");
4853e12c5d1SDavid du Colombier 
4863e12c5d1SDavid du Colombier 	/* >> and | deserve different flavored messages */
4873e12c5d1SDavid du Colombier 	switch(dp->status) {
4883e12c5d1SDavid du Colombier 	case d_pipe:
4893e12c5d1SDavid du Colombier 		s_append(errstring, "The mailer `");
4903e12c5d1SDavid du Colombier 		s_append(errstring, s_to_c(dp->repl1));
491d9306527SDavid du Colombier 		sprint(smsg, "' returned error status %x.\n\n", status);
4923e12c5d1SDavid du Colombier 		s_append(errstring, smsg);
4933e12c5d1SDavid du Colombier 		break;
4943e12c5d1SDavid du Colombier 	}
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	s_free(sender);
4973e12c5d1SDavid du Colombier }
4983e12c5d1SDavid du Colombier 
4993e12c5d1SDavid du Colombier /*
500d9306527SDavid du Colombier  *  create a new boundary
501d9306527SDavid du Colombier  */
502d9306527SDavid du Colombier static String*
mkboundary(void)503d9306527SDavid du Colombier mkboundary(void)
504d9306527SDavid du Colombier {
505d9306527SDavid du Colombier 	char buf[32];
506d9306527SDavid du Colombier 	int i;
507d9306527SDavid du Colombier 	static int already;
508d9306527SDavid du Colombier 
509d9306527SDavid du Colombier 	if(already == 0){
510d9306527SDavid du Colombier 		srand((time(0)<<16)|getpid());
511d9306527SDavid du Colombier 		already = 1;
512d9306527SDavid du Colombier 	}
513d9306527SDavid du Colombier 	strcpy(buf, "upas-");
514d9306527SDavid du Colombier 	for(i = 5; i < sizeof(buf)-1; i++)
515d9306527SDavid du Colombier 		buf[i] = 'a' + nrand(26);
516d9306527SDavid du Colombier 	buf[i] = 0;
517d9306527SDavid du Colombier 	return s_copy(buf);
518d9306527SDavid du Colombier }
519d9306527SDavid du Colombier 
520d9306527SDavid du Colombier /*
5213e12c5d1SDavid du Colombier  *  reply with up to 1024 characters of the
5223e12c5d1SDavid du Colombier  *  original message
5233e12c5d1SDavid du Colombier  */
5243e12c5d1SDavid du Colombier static int
replymsg(String * errstring,message * mp,dest * dp)5253e12c5d1SDavid du Colombier replymsg(String *errstring, message *mp, dest *dp)
5263e12c5d1SDavid du Colombier {
5273e12c5d1SDavid du Colombier 	message *refp = m_new();
5283e12c5d1SDavid du Colombier 	dest *ndp;
5293e12c5d1SDavid du Colombier 	char *rcvr;
5303e12c5d1SDavid du Colombier 	int rv;
531d9306527SDavid du Colombier 	String *boundary;
532d9306527SDavid du Colombier 
533d9306527SDavid du Colombier 	boundary = mkboundary();
5343e12c5d1SDavid du Colombier 
5357dd7cddfSDavid du Colombier 	refp->bulk = 1;
53668060204SDavid du Colombier 	refp->rfc822headers = 1;
5373e12c5d1SDavid du Colombier 	rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr);
5383e12c5d1SDavid du Colombier 	ndp = d_new(s_copy(rcvr));
5393e12c5d1SDavid du Colombier 	s_append(refp->sender, "postmaster");
5407dd7cddfSDavid du Colombier 	s_append(refp->replyaddr, "/dev/null");
5413e12c5d1SDavid du Colombier 	s_append(refp->date, thedate());
54268060204SDavid du Colombier 	refp->haveto = 1;
54368060204SDavid du Colombier 	s_append(refp->body, "To: ");
54468060204SDavid du Colombier 	s_append(refp->body, rcvr);
54568060204SDavid du Colombier 	s_append(refp->body, "\n");
546d9306527SDavid du Colombier 	s_append(refp->body, "Subject: bounced mail\n");
547d9306527SDavid du Colombier 	s_append(refp->body, "MIME-Version: 1.0\n");
548d9306527SDavid du Colombier 	s_append(refp->body, "Content-Type: multipart/mixed;\n");
549d9306527SDavid du Colombier 	s_append(refp->body, "\tboundary=\"");
550d9306527SDavid du Colombier 	s_append(refp->body, s_to_c(boundary));
551d9306527SDavid du Colombier 	s_append(refp->body, "\"\n");
552d9306527SDavid du Colombier 	s_append(refp->body, "Content-Disposition: inline\n");
553d9306527SDavid du Colombier 	s_append(refp->body, "\n");
554d9306527SDavid du Colombier 	s_append(refp->body, "This is a multi-part message in MIME format.\n");
555d9306527SDavid du Colombier 	s_append(refp->body, "--");
556d9306527SDavid du Colombier 	s_append(refp->body, s_to_c(boundary));
557d9306527SDavid du Colombier 	s_append(refp->body, "\n");
558d9306527SDavid du Colombier 	s_append(refp->body, "Content-Disposition: inline\n");
559d9306527SDavid du Colombier 	s_append(refp->body, "Content-Type: text/plain; charset=\"US-ASCII\"\n");
560d9306527SDavid du Colombier 	s_append(refp->body, "Content-Transfer-Encoding: 7bit\n");
561d9306527SDavid du Colombier 	s_append(refp->body, "\n");
562d9306527SDavid du Colombier 	s_append(refp->body, "The attached mail");
5633e12c5d1SDavid du Colombier 	s_append(refp->body, s_to_c(errstring));
564d9306527SDavid du Colombier 	s_append(refp->body, "--");
565d9306527SDavid du Colombier 	s_append(refp->body, s_to_c(boundary));
566d9306527SDavid du Colombier 	s_append(refp->body, "\n");
567d9306527SDavid du Colombier 	s_append(refp->body, "Content-Type: message/rfc822\n");
568d9306527SDavid du Colombier 	s_append(refp->body, "Content-Disposition: inline\n\n");
569d9306527SDavid du Colombier 	s_append(refp->body, s_to_c(mp->body));
570d9306527SDavid du Colombier 	s_append(refp->body, "--");
571d9306527SDavid du Colombier 	s_append(refp->body, s_to_c(boundary));
572d9306527SDavid du Colombier 	s_append(refp->body, "--\n");
573d9306527SDavid du Colombier 
5747dd7cddfSDavid du Colombier 	refp->size = s_len(refp->body);
5753e12c5d1SDavid du Colombier 	rv = send(ndp, refp, 0);
5763e12c5d1SDavid du Colombier 	m_free(refp);
5773e12c5d1SDavid du Colombier 	d_free(ndp);
5783e12c5d1SDavid du Colombier 	return rv;
5793e12c5d1SDavid du Colombier }
580