xref: /plan9/sys/src/cmd/upas/scanmail/scanmail.c (revision 4d44ba9b9ee4246ddbd96c7fcaf0918ab92ab35a)
17dd7cddfSDavid du Colombier #include "common.h"
280ee5cbfSDavid du Colombier #include "spam.h"
37dd7cddfSDavid du Colombier 
47dd7cddfSDavid du Colombier int	cflag;
57dd7cddfSDavid du Colombier int	debug;
67dd7cddfSDavid du Colombier int	hflag;
77dd7cddfSDavid du Colombier int	nflag;
87dd7cddfSDavid du Colombier int	sflag;
97dd7cddfSDavid du Colombier int	tflag;
107dd7cddfSDavid du Colombier int	vflag;
117dd7cddfSDavid du Colombier Biobuf	bin, bout, *cout;
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier 	/* file names */
147dd7cddfSDavid du Colombier char	patfile[128];
157dd7cddfSDavid du Colombier char	linefile[128];
167dd7cddfSDavid du Colombier char	holdqueue[128];
177dd7cddfSDavid du Colombier char	copydir[128];
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier char	header[Hdrsize+2];
20223a736eSDavid du Colombier char	cmd[1024];
217dd7cddfSDavid du Colombier char	**qname;
227dd7cddfSDavid du Colombier char	**qdir;
237dd7cddfSDavid du Colombier char	*sender;
247dd7cddfSDavid du Colombier String	*recips;
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier char*	canon(Biobuf*, char*, char*, int*);
2780ee5cbfSDavid du Colombier int	matcher(char*, Pattern*, char*, Resub*);
2880ee5cbfSDavid du Colombier int	matchaction(int, char*, Resub*);
297dd7cddfSDavid du Colombier Biobuf	*opencopy(char*);
307dd7cddfSDavid du Colombier Biobuf	*opendump(char*);
317dd7cddfSDavid du Colombier char	*qmail(char**, char*, int, Biobuf*);
327dd7cddfSDavid du Colombier void	saveline(char*, char*, Resub*);
336b6b9ac8SDavid du Colombier int	optoutofspamfilter(char*);
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier void
usage(void)367dd7cddfSDavid du Colombier usage(void)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier 	fprint(2, "missing or bad arguments to qer\n");
397dd7cddfSDavid du Colombier 	exits("usage");
407dd7cddfSDavid du Colombier }
417dd7cddfSDavid du Colombier 
42fb7f0c93SDavid du Colombier void
regerror(char * s)43fb7f0c93SDavid du Colombier regerror(char *s)
44fb7f0c93SDavid du Colombier {
45fb7f0c93SDavid du Colombier 	fprint(2, "scanmail: %s\n", s);
46fb7f0c93SDavid du Colombier }
47fb7f0c93SDavid du Colombier 
487dd7cddfSDavid du Colombier void *
Malloc(long n)497dd7cddfSDavid du Colombier Malloc(long n)
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier 	void *p;
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier 	p = malloc(n);
547dd7cddfSDavid du Colombier 	if(p == 0)
557dd7cddfSDavid du Colombier 		exits("malloc");
567dd7cddfSDavid du Colombier 	return p;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier 
5980ee5cbfSDavid du Colombier void*
Realloc(void * p,ulong n)6080ee5cbfSDavid du Colombier Realloc(void *p, ulong n)
6180ee5cbfSDavid du Colombier {
6280ee5cbfSDavid du Colombier 	p = realloc(p, n);
6380ee5cbfSDavid du Colombier 	if(p == 0)
6480ee5cbfSDavid du Colombier 		exits("realloc");
6580ee5cbfSDavid du Colombier 	return p;
6680ee5cbfSDavid du Colombier }
6780ee5cbfSDavid du Colombier 
687dd7cddfSDavid du Colombier void
main(int argc,char * argv[])697dd7cddfSDavid du Colombier main(int argc, char *argv[])
707dd7cddfSDavid du Colombier {
716b6b9ac8SDavid du Colombier 	int i, n, nolines, optout;
727dd7cddfSDavid du Colombier 	char **args, **a, *cp, *buf;
7380ee5cbfSDavid du Colombier 	char body[Bodysize+2];
747dd7cddfSDavid du Colombier 	Resub match[1];
757dd7cddfSDavid du Colombier 	Biobuf *bp;
767dd7cddfSDavid du Colombier 
776b6b9ac8SDavid du Colombier 	optout = 1;
787dd7cddfSDavid du Colombier 	a = args = Malloc((argc+1)*sizeof(char*));
797dd7cddfSDavid du Colombier 	sprint(patfile, "%s/patterns", UPASLIB);
807dd7cddfSDavid du Colombier 	sprint(linefile, "%s/lines", UPASLOG);
817dd7cddfSDavid du Colombier 	sprint(holdqueue, "%s/queue.hold", SPOOL);
827dd7cddfSDavid du Colombier 	sprint(copydir, "%s/copy", SPOOL);
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier 	*a++ = argv[0];
857dd7cddfSDavid du Colombier 	for(argc--, argv++; argv[0] && argv[0][0] == '-'; argc--, argv++){
867dd7cddfSDavid du Colombier 		switch(argv[0][1]){
877dd7cddfSDavid du Colombier 		case 'c':			/* save copy of message */
887dd7cddfSDavid du Colombier 			cflag = 1;
897dd7cddfSDavid du Colombier 			break;
907dd7cddfSDavid du Colombier 		case 'd':			/* debug */
917dd7cddfSDavid du Colombier 			debug++;
927dd7cddfSDavid du Colombier 			*a++ = argv[0];
937dd7cddfSDavid du Colombier 			break;
947dd7cddfSDavid du Colombier 		case 'h':			/* queue held messages by sender domain */
957dd7cddfSDavid du Colombier 			hflag = 1;		/* -q flag must be set also */
967dd7cddfSDavid du Colombier 			break;
977dd7cddfSDavid du Colombier 		case 'n':			/* NOHOLD mode */
987dd7cddfSDavid du Colombier 			nflag = 1;
997dd7cddfSDavid du Colombier 			break;
1007dd7cddfSDavid du Colombier 		case 'p':			/* pattern file */
1017dd7cddfSDavid du Colombier 			if(argv[0][2] || argv[1] == 0)
1027dd7cddfSDavid du Colombier 				usage();
1037dd7cddfSDavid du Colombier 			argc--;
1047dd7cddfSDavid du Colombier 			argv++;
105*4d44ba9bSDavid du Colombier 			strecpy(patfile, patfile+sizeof patfile, *argv);
1067dd7cddfSDavid du Colombier 			break;
1077dd7cddfSDavid du Colombier 		case 'q':			/* queue name */
1087dd7cddfSDavid du Colombier 			if(argv[0][2] ||  argv[1] == 0)
1097dd7cddfSDavid du Colombier 				usage();
1107dd7cddfSDavid du Colombier 			*a++ = argv[0];
1117dd7cddfSDavid du Colombier 			argc--;
1127dd7cddfSDavid du Colombier 			argv++;
1137dd7cddfSDavid du Colombier 			qname = a;
1147dd7cddfSDavid du Colombier 			*a++ = argv[0];
1157dd7cddfSDavid du Colombier 			break;
1167dd7cddfSDavid du Colombier 		case 's':			/* save copy of dumped message */
1177dd7cddfSDavid du Colombier 			sflag = 1;
1187dd7cddfSDavid du Colombier 			break;
1197dd7cddfSDavid du Colombier 		case 't':			/* test mode - don't log match
1207dd7cddfSDavid du Colombier 						 * and write message to /dev/null
1217dd7cddfSDavid du Colombier 						 */
1227dd7cddfSDavid du Colombier 			tflag = 1;
1237dd7cddfSDavid du Colombier 			break;
1247dd7cddfSDavid du Colombier 		case 'v':			/* vebose - print matches */
1257dd7cddfSDavid du Colombier 			vflag = 1;
1267dd7cddfSDavid du Colombier 			break;
1277dd7cddfSDavid du Colombier 		default:
1287dd7cddfSDavid du Colombier 			*a++ = argv[0];
1297dd7cddfSDavid du Colombier 			break;
1307dd7cddfSDavid du Colombier 		}
1317dd7cddfSDavid du Colombier 	}
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier 	if(argc < 3)
1347dd7cddfSDavid du Colombier 		usage();
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier 	Binit(&bin, 0, OREAD);
1377dd7cddfSDavid du Colombier 	bp = Bopen(patfile, OREAD);
1387dd7cddfSDavid du Colombier 	if(bp){
1397dd7cddfSDavid du Colombier 		parsepats(bp);
1407dd7cddfSDavid du Colombier 		Bterm(bp);
1417dd7cddfSDavid du Colombier 	}
1427dd7cddfSDavid du Colombier 	qdir = a;
1437dd7cddfSDavid du Colombier 	sender = argv[2];
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier 		/* copy the rest of argv, acummulating the recipients as we go */
1467dd7cddfSDavid du Colombier 	for(i = 0; argv[i]; i++){
1477dd7cddfSDavid du Colombier 		*a++ = argv[i];
1487dd7cddfSDavid du Colombier 		if(i < 4)	/* skip queue, 'mail', sender, dest sys */
1497dd7cddfSDavid du Colombier 			continue;
1507dd7cddfSDavid du Colombier 			/* recipients and smtp flags - skip the latter*/
1517dd7cddfSDavid du Colombier 		if(strcmp(argv[i], "-g") == 0){
1527dd7cddfSDavid du Colombier 			*a++ = argv[++i];
1537dd7cddfSDavid du Colombier 			continue;
1547dd7cddfSDavid du Colombier 		}
1557dd7cddfSDavid du Colombier 		if(recips)
1567dd7cddfSDavid du Colombier 			s_append(recips, ", ");
1577dd7cddfSDavid du Colombier 		else
1587dd7cddfSDavid du Colombier 			recips = s_new();
1597dd7cddfSDavid du Colombier 		s_append(recips, argv[i]);
1606b6b9ac8SDavid du Colombier 		if(optout && !optoutofspamfilter(argv[i]))
1616b6b9ac8SDavid du Colombier 			optout = 0;
1627dd7cddfSDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 	*a = 0;
1647dd7cddfSDavid du Colombier 		/* construct a command string for matching */
1657dd7cddfSDavid du Colombier 	snprint(cmd, sizeof(cmd)-1, "%s %s", sender, s_to_c(recips));
1667dd7cddfSDavid du Colombier 	cmd[sizeof(cmd)-1] = 0;
1677dd7cddfSDavid du Colombier 	for(cp = cmd; *cp; cp++)
1687dd7cddfSDavid du Colombier 		*cp = tolower(*cp);
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 		/* canonicalize a copy of the header and body.
1717dd7cddfSDavid du Colombier 		 * buf points to orginal message and n contains
1727dd7cddfSDavid du Colombier 		 * number of bytes of original message read during
1737dd7cddfSDavid du Colombier 		 * canonicalization.
1747dd7cddfSDavid du Colombier 		 */
1757dd7cddfSDavid du Colombier 	*body = 0;
1767dd7cddfSDavid du Colombier 	*header = 0;
1777dd7cddfSDavid du Colombier 	buf = canon(&bin, header+1, body+1, &n);
1787dd7cddfSDavid du Colombier 	if (buf == 0)
1797dd7cddfSDavid du Colombier 		exits("read");
1807dd7cddfSDavid du Colombier 
1816b6b9ac8SDavid du Colombier 		/* if all users opt out, don't try matches */
1826b6b9ac8SDavid du Colombier 	if(optout){
1836b6b9ac8SDavid du Colombier 		if(cflag)
1846b6b9ac8SDavid du Colombier 			cout = opencopy(sender);
1856b6b9ac8SDavid du Colombier 		exits(qmail(args, buf, n, cout));
1866b6b9ac8SDavid du Colombier 	}
1876b6b9ac8SDavid du Colombier 
18880ee5cbfSDavid du Colombier 		/* Turn off line logging, if command line matches */
18980ee5cbfSDavid du Colombier 	nolines = matchaction(Lineoff, cmd, match);
1907dd7cddfSDavid du Colombier 
19180ee5cbfSDavid du Colombier 	for(i = 0; patterns[i].action; i++){
19280ee5cbfSDavid du Colombier 			/* Lineoff patterns were already done above */
19380ee5cbfSDavid du Colombier 		if(i == Lineoff)
1947dd7cddfSDavid du Colombier 			continue;
19580ee5cbfSDavid du Colombier 			/* don't apply "Line" patterns if excluded above */
19680ee5cbfSDavid du Colombier 		if(nolines && i == SaveLine)
1977dd7cddfSDavid du Colombier 			continue;
19880ee5cbfSDavid du Colombier 			/* apply patterns to the sender/recips, header and body */
19980ee5cbfSDavid du Colombier 		if(matchaction(i, cmd, match))
20080ee5cbfSDavid du Colombier 			break;
20180ee5cbfSDavid du Colombier 		if(matchaction(i, header+1, match))
20280ee5cbfSDavid du Colombier 			break;
20380ee5cbfSDavid du Colombier 		if(i == HoldHeader)
20480ee5cbfSDavid du Colombier 			continue;
20580ee5cbfSDavid du Colombier 		if(matchaction(i, body+1, match))
20680ee5cbfSDavid du Colombier 			break;
2077dd7cddfSDavid du Colombier 	}
20880ee5cbfSDavid du Colombier 	if(cflag && patterns[i].action == 0)	/* no match found - save msg */
2097dd7cddfSDavid du Colombier 		cout = opencopy(sender);
21080ee5cbfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	exits(qmail(args, buf, n, cout));
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier char*
qmail(char ** argv,char * buf,int n,Biobuf * cout)2157dd7cddfSDavid du Colombier qmail(char **argv, char *buf, int n, Biobuf *cout)
2167dd7cddfSDavid du Colombier {
2179a747e4fSDavid du Colombier 	Waitmsg *status;
2189a747e4fSDavid du Colombier 	int i, pid, pipefd[2];
2197dd7cddfSDavid du Colombier 	char path[512];
2207dd7cddfSDavid du Colombier 	Biobuf *bp;
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 	pid = 0;
2237dd7cddfSDavid du Colombier 	if(tflag == 0){
2247dd7cddfSDavid du Colombier 		if(pipe(pipefd) < 0)
2257dd7cddfSDavid du Colombier 			exits("pipe");
2267dd7cddfSDavid du Colombier 		pid = fork();
2277dd7cddfSDavid du Colombier 		if(pid == 0){
2287dd7cddfSDavid du Colombier 			dup(pipefd[0], 0);
2297dd7cddfSDavid du Colombier 			for(i = sysfiles(); i >= 3; i--)
2307dd7cddfSDavid du Colombier 				close(i);
2317dd7cddfSDavid du Colombier 			snprint(path, sizeof(path), "%s/qer", UPASBIN);
2327dd7cddfSDavid du Colombier 			*argv=path;
2337dd7cddfSDavid du Colombier 			exec(path, argv);
2347dd7cddfSDavid du Colombier 			exits("exec");
2357dd7cddfSDavid du Colombier 		}
2367dd7cddfSDavid du Colombier 		Binit(&bout, pipefd[1], OWRITE);
2377dd7cddfSDavid du Colombier 		bp = &bout;
2387dd7cddfSDavid du Colombier 	} else
2397dd7cddfSDavid du Colombier 		bp = Bopen("/dev/null", OWRITE);
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	while(n > 0){
2427dd7cddfSDavid du Colombier 		Bwrite(bp, buf, n);
2437dd7cddfSDavid du Colombier 		if(cout)
2447dd7cddfSDavid du Colombier 			Bwrite(cout, buf, n);
2457dd7cddfSDavid du Colombier 		n = Bread(&bin, buf, sizeof(buf)-1);
2467dd7cddfSDavid du Colombier 	}
2477dd7cddfSDavid du Colombier 	Bterm(bp);
2487dd7cddfSDavid du Colombier 	if(cout)
2497dd7cddfSDavid du Colombier 		Bterm(cout);
2507dd7cddfSDavid du Colombier 	if(tflag)
2517dd7cddfSDavid du Colombier 		return 0;
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 	close(pipefd[1]);
2547dd7cddfSDavid du Colombier 	close(pipefd[0]);
2557dd7cddfSDavid du Colombier 	for(;;){
2569a747e4fSDavid du Colombier 		status = wait();
2579a747e4fSDavid du Colombier 		if(status == nil || status->pid == pid)
2587dd7cddfSDavid du Colombier 			break;
2599a747e4fSDavid du Colombier 		free(status);
2607dd7cddfSDavid du Colombier 	}
2619a747e4fSDavid du Colombier 	if(status == nil)
2629a747e4fSDavid du Colombier 		strcpy(buf, "wait failed");
2639a747e4fSDavid du Colombier 	else{
2649a747e4fSDavid du Colombier 		strcpy(buf, status->msg);
2659a747e4fSDavid du Colombier 		free(status);
2669a747e4fSDavid du Colombier 	}
2677dd7cddfSDavid du Colombier 	return buf;
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier 
27080ee5cbfSDavid du Colombier char*
canon(Biobuf * bp,char * header,char * body,int * n)27180ee5cbfSDavid du Colombier canon(Biobuf *bp, char *header, char *body, int *n)
2727dd7cddfSDavid du Colombier {
27380ee5cbfSDavid du Colombier 	int hsize;
27480ee5cbfSDavid du Colombier 	char *raw;
27580ee5cbfSDavid du Colombier 
27680ee5cbfSDavid du Colombier 	hsize = 0;
27780ee5cbfSDavid du Colombier 	*header = 0;
27880ee5cbfSDavid du Colombier 	*body = 0;
27980ee5cbfSDavid du Colombier 	raw = readmsg(bp, &hsize, n);
28080ee5cbfSDavid du Colombier 	if(raw){
2819a747e4fSDavid du Colombier 		if(convert(raw, raw+hsize, header, Hdrsize, 0))
2829a747e4fSDavid du Colombier 			conv64(raw+hsize, raw+*n, body, Bodysize);	/* base64 */
2839a747e4fSDavid du Colombier 		else
2849a747e4fSDavid du Colombier 			convert(raw+hsize, raw+*n, body, Bodysize, 1);	/* text */
28580ee5cbfSDavid du Colombier 	}
28680ee5cbfSDavid du Colombier 	return raw;
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier int
matchaction(int action,char * message,Resub * m)29080ee5cbfSDavid du Colombier matchaction(int action, char *message, Resub *m)
29180ee5cbfSDavid du Colombier {
29280ee5cbfSDavid du Colombier 	char *name;
29380ee5cbfSDavid du Colombier 	Pattern *p;
29480ee5cbfSDavid du Colombier 
29580ee5cbfSDavid du Colombier 	if(message == 0 || *message == 0)
29680ee5cbfSDavid du Colombier 		return 0;
29780ee5cbfSDavid du Colombier 
29880ee5cbfSDavid du Colombier 	name = patterns[action].action;
29980ee5cbfSDavid du Colombier 	p = patterns[action].strings;
30080ee5cbfSDavid du Colombier 	if(p)
30180ee5cbfSDavid du Colombier 		if(matcher(name, p, message, m))
30280ee5cbfSDavid du Colombier 			return 1;
30380ee5cbfSDavid du Colombier 
30480ee5cbfSDavid du Colombier 	for(p = patterns[action].regexps; p; p = p->next)
30580ee5cbfSDavid du Colombier 		if(matcher(name, p, message, m))
30680ee5cbfSDavid du Colombier 			return 1;
30780ee5cbfSDavid du Colombier 	return 0;
30880ee5cbfSDavid du Colombier }
30980ee5cbfSDavid du Colombier 
31080ee5cbfSDavid du Colombier int
matcher(char * action,Pattern * p,char * message,Resub * m)31180ee5cbfSDavid du Colombier matcher(char *action, Pattern *p, char *message, Resub *m)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier 	char *cp;
3147dd7cddfSDavid du Colombier 	String *s;
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier 	for(cp = message; matchpat(p, cp, m); cp = m->ep){
31780ee5cbfSDavid du Colombier 		switch(p->action){
3187dd7cddfSDavid du Colombier 		case SaveLine:
3197dd7cddfSDavid du Colombier 			if(vflag)
32080ee5cbfSDavid du Colombier 				xprint(2, action, m);
3217dd7cddfSDavid du Colombier 			saveline(linefile, sender, m);
3227dd7cddfSDavid du Colombier 			break;
3237dd7cddfSDavid du Colombier 		case HoldHeader:
3247dd7cddfSDavid du Colombier 		case Hold:
3257dd7cddfSDavid du Colombier 			if(nflag)
3267dd7cddfSDavid du Colombier 				continue;
3277dd7cddfSDavid du Colombier 			if(vflag)
32880ee5cbfSDavid du Colombier 				xprint(2, action, m);
3297dd7cddfSDavid du Colombier 			*qdir = holdqueue;
3307dd7cddfSDavid du Colombier 			if(hflag && qname){
3317dd7cddfSDavid du Colombier 				cp = strchr(sender, '!');
3327dd7cddfSDavid du Colombier 				if(cp){
3337dd7cddfSDavid du Colombier 					*cp = 0;
3347dd7cddfSDavid du Colombier 					*qname = strdup(sender);
3357dd7cddfSDavid du Colombier 					*cp = '!';
3367dd7cddfSDavid du Colombier 				} else
3377dd7cddfSDavid du Colombier 					*qname = strdup(sender);
3387dd7cddfSDavid du Colombier 			}
3397dd7cddfSDavid du Colombier 			return 1;
3407dd7cddfSDavid du Colombier 		case Dump:
3417dd7cddfSDavid du Colombier 			if(vflag)
34280ee5cbfSDavid du Colombier 				xprint(2, action, m);
3437dd7cddfSDavid du Colombier 			*(m->ep) = 0;
3447dd7cddfSDavid du Colombier 			if(!tflag){
3457dd7cddfSDavid du Colombier 				s = s_new();
3467dd7cddfSDavid du Colombier 				s_append(s, sender);
3477dd7cddfSDavid du Colombier 				s = unescapespecial(s);
3487dd7cddfSDavid du Colombier 				syslog(0, "smtpd", "Dumped %s [%s] to %s", s_to_c(s), m->sp,
3497dd7cddfSDavid du Colombier 					s_to_c(s_restart(recips)));
3507dd7cddfSDavid du Colombier 				s_free(s);
3517dd7cddfSDavid du Colombier 			}
3527dd7cddfSDavid du Colombier 			tflag = 1;
3537dd7cddfSDavid du Colombier 			if(sflag)
3547dd7cddfSDavid du Colombier 				cout = opendump(sender);
3557dd7cddfSDavid du Colombier 			return 1;
3567dd7cddfSDavid du Colombier 		default:
3577dd7cddfSDavid du Colombier 			break;
3587dd7cddfSDavid du Colombier 		}
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier 	return 0;
3617dd7cddfSDavid du Colombier }
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier void
saveline(char * file,char * sender,Resub * rp)3647dd7cddfSDavid du Colombier saveline(char *file, char *sender, Resub *rp)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier 	char *p, *q;
3677dd7cddfSDavid du Colombier 	int i, c;
3687dd7cddfSDavid du Colombier 	Biobuf *bp;
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier 	if(rp->sp == 0 || rp->ep == 0)
3717dd7cddfSDavid du Colombier 		return;
3727dd7cddfSDavid du Colombier 		/* back up approx 20 characters to whitespace */
3737dd7cddfSDavid du Colombier 	for(p = rp->sp, i = 0; *p && i < 20; i++, p--)
3747dd7cddfSDavid du Colombier 			;
3757dd7cddfSDavid du Colombier 	while(*p && *p != ' ')
3767dd7cddfSDavid du Colombier 		p--;
3777dd7cddfSDavid du Colombier 	p++;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 		/* grab about 20 more chars beyond the end of the match */
3807dd7cddfSDavid du Colombier 	for(q = rp->ep, i = 0; *q && i < 20; i++, q++)
3817dd7cddfSDavid du Colombier 			;
3827dd7cddfSDavid du Colombier 	while(*q && *q != ' ')
3837dd7cddfSDavid du Colombier 		q++;
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier 	c = *q;
3867dd7cddfSDavid du Colombier 	*q = 0;
3877dd7cddfSDavid du Colombier 	bp = sysopen(file, "al", 0644);
3887dd7cddfSDavid du Colombier 	if(bp){
3897dd7cddfSDavid du Colombier 		Bprint(bp, "%s-> %s\n", sender, p);
3907dd7cddfSDavid du Colombier 		Bterm(bp);
3917dd7cddfSDavid du Colombier 	}
3927dd7cddfSDavid du Colombier 	else if(debug)
3937dd7cddfSDavid du Colombier 		fprint(2, "can't save line: (%s) %s\n", sender, p);
3947dd7cddfSDavid du Colombier 	*q = c;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier Biobuf*
opendump(char * sender)3987dd7cddfSDavid du Colombier opendump(char *sender)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier 	int i;
4017dd7cddfSDavid du Colombier 	ulong h;
4027dd7cddfSDavid du Colombier 	char buf[512];
4037dd7cddfSDavid du Colombier 	Biobuf *b;
4047dd7cddfSDavid du Colombier 	char *cp;
4057dd7cddfSDavid du Colombier 
4067dd7cddfSDavid du Colombier 	cp = ctime(time(0));
4077dd7cddfSDavid du Colombier 	cp[7] = 0;
4087dd7cddfSDavid du Colombier 	cp[10] = 0;
4097dd7cddfSDavid du Colombier 	if(cp[8] == ' ')
4107dd7cddfSDavid du Colombier 		sprint(buf, "%s/queue.dump/%s%c", SPOOL, cp+4, cp[9]);
4117dd7cddfSDavid du Colombier 	else
4127dd7cddfSDavid du Colombier 		sprint(buf, "%s/queue.dump/%s%c%c", SPOOL, cp+4, cp[8], cp[9]);
4137dd7cddfSDavid du Colombier 	cp = buf+strlen(buf);
4149a747e4fSDavid du Colombier 	if(access(buf, 0) < 0 && sysmkdir(buf, 0777) < 0){
4159a747e4fSDavid du Colombier 		syslog(0, "smtpd", "couldn't dump mail from %s: %r", sender);
4167dd7cddfSDavid du Colombier 		return 0;
4179a747e4fSDavid du Colombier 	}
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier 	h = 0;
4207dd7cddfSDavid du Colombier 	while(*sender)
4217dd7cddfSDavid du Colombier 		h = h*257 + *sender++;
4227dd7cddfSDavid du Colombier 	for(i = 0; i < 50; i++){
4237dd7cddfSDavid du Colombier 		h += lrand();
4247dd7cddfSDavid du Colombier 		sprint(cp, "/%lud", h);
42580ee5cbfSDavid du Colombier 		b = sysopen(buf, "wlc", 0644);
4267dd7cddfSDavid du Colombier 		if(b){
4277dd7cddfSDavid du Colombier 			if(vflag)
4287dd7cddfSDavid du Colombier 				fprint(2, "saving in %s\n", buf);
4297dd7cddfSDavid du Colombier 			return b;
4307dd7cddfSDavid du Colombier 		}
4317dd7cddfSDavid du Colombier 	}
4327dd7cddfSDavid du Colombier 	return 0;
4337dd7cddfSDavid du Colombier }
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier Biobuf*
opencopy(char * sender)4367dd7cddfSDavid du Colombier opencopy(char *sender)
4377dd7cddfSDavid du Colombier {
4387dd7cddfSDavid du Colombier 	int i;
4397dd7cddfSDavid du Colombier 	ulong h;
4407dd7cddfSDavid du Colombier 	char buf[512];
4417dd7cddfSDavid du Colombier 	Biobuf *b;
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	h = 0;
4447dd7cddfSDavid du Colombier 	while(*sender)
4457dd7cddfSDavid du Colombier 		h = h*257 + *sender++;
4467dd7cddfSDavid du Colombier 	for(i = 0; i < 50; i++){
4477dd7cddfSDavid du Colombier 		h += lrand();
4487dd7cddfSDavid du Colombier 		sprint(buf, "%s/%lud", copydir, h);
4497dd7cddfSDavid du Colombier 		b = sysopen(buf, "wlc", 0600);
4507dd7cddfSDavid du Colombier 		if(b)
4517dd7cddfSDavid du Colombier 			return b;
4527dd7cddfSDavid du Colombier 	}
4537dd7cddfSDavid du Colombier 	return 0;
4547dd7cddfSDavid du Colombier }
4556b6b9ac8SDavid du Colombier 
4566b6b9ac8SDavid du Colombier int
optoutofspamfilter(char * addr)4576b6b9ac8SDavid du Colombier optoutofspamfilter(char *addr)
4586b6b9ac8SDavid du Colombier {
4596b6b9ac8SDavid du Colombier 	char *p, *f;
4606b6b9ac8SDavid du Colombier 	int rv;
4616b6b9ac8SDavid du Colombier 
4626b6b9ac8SDavid du Colombier 	p = strchr(addr, '!');
4636b6b9ac8SDavid du Colombier 	if(p)
4646b6b9ac8SDavid du Colombier 		p++;
4656b6b9ac8SDavid du Colombier 	else
4666b6b9ac8SDavid du Colombier 		p = addr;
4676b6b9ac8SDavid du Colombier 
4686b6b9ac8SDavid du Colombier 	rv = 0;
4696b6b9ac8SDavid du Colombier 	f = smprint("/mail/box/%s/nospamfiltering", p);
4706b6b9ac8SDavid du Colombier 	if(f != nil){
4716b6b9ac8SDavid du Colombier 		rv = access(f, 0)==0;
4726b6b9ac8SDavid du Colombier 		free(f);
4736b6b9ac8SDavid du Colombier 	}
4746b6b9ac8SDavid du Colombier 
4756b6b9ac8SDavid du Colombier 	return rv;
4766b6b9ac8SDavid du Colombier }
477