#include "common.h"
#include <regexp.h>
#include "spam.h"

int 	debug;
Biobuf	bin;
char	patfile[128], header[Hdrsize+2];
char	cmd[1024];

char*	canon(Biobuf*, char*, char*, int*);
int	matcher(char *, Pattern*, char*, Resub*);
int	matchaction(Patterns*, char*);

void
usage(void)
{
	fprint(2, "usage: testscan -avd [-p pattern] ...\n");
	exits("usage");
}

void *
Malloc(long n)
{
	void *p;

	p = malloc(n);
	if(p == nil)
		sysfatal("malloc: %r");
	setmalloctag(p, getcallerpc(&n));
	return p;
}

void*
Realloc(void *p, ulong n)
{
	p = realloc(p, n);
	if(p == nil)
		sysfatal("malloc: %r");
	setrealloctag(p, getcallerpc(&p));
	return p;
}

void
dumppats(void)
{
	int i, j;
	Pattern *p;
	Spat *s, *q;

	for(i = 0; patterns[i].action; i++){
		for(p = patterns[i].regexps; p; p = p->next){
			print("%s <REGEXP>\n", patterns[i].action);
			if(p->alt)
				print("Alt:");
			for(s = p->alt; s; s = s->next)
				print("\t%s\n", s->string);
		}
		p = patterns[i].strings;
		if(p == 0)
			continue;

		for(j = 0; j < Nhash; j++){
			for(s = p->spat[j]; s; s = s->next){
				print("%s %s\n", patterns[i].action, s->string);
				if(s->alt)
					print("Alt:");
				for(q = s->alt; q; q = q->next)
					print("\t%s\n", q->string);
			}
		}
	}
}

void
main(int argc, char *argv[])
{
	int i, fd, n, aflag, vflag;
	char body[Bodysize+2], *raw, *ret;
	Biobuf *bp;

	snprint(patfile, sizeof patfile, "%s/patterns", UPASLIB);
	aflag = -1;
	vflag = 0;
	ARGBEGIN {
	case 'a':
		aflag = 1;
		break;
	case 'v':
		vflag = 1;
		break;
	case 'd':
		debug++;
		break;
	case 'p':
		snprint(patfile, sizeof patfile, "%s", EARGF(usage()));
		break;
	} ARGEND

	bp = Bopen(patfile, OREAD);
	if(bp){
		parsepats(bp);
		Bterm(bp);
	}

	if(argc >= 1){
		fd = open(*argv, OREAD);
		if(fd < 0){
			fprint(2, "can't open %s\n", *argv);
			exits("open");
		}
		Binit(&bin, fd, OREAD);
	} else 
		Binit(&bin, 0, OREAD);

	*body = 0;
	*header = 0;
	ret = 0;
	for(;;){
		raw = canon(&bin, header+1, body+1, &n);
		if(raw == 0)
			break;
		if(aflag == 0)
			continue;
		if(aflag < 0)
			aflag = 0;
		if(vflag){
			if(header[1]) {
				fprint(2, "\t**** Header ****\n\n");
				write(2, header+1, strlen(header+1));
				fprint(2, "\n");
			}
			fprint(2, "\t**** Body ****\n\n");
			if(body[1])
				write(2, body+1, strlen(body+1));
			fprint(2, "\n");
		}

		for(i = 0; patterns[i].action; i++){
			if(matchaction(&patterns[i], header+1))
				ret = patterns[i].action;
			if(i == HoldHeader)
				continue;
			if(matchaction(&patterns[i], body+1))
				ret = patterns[i].action;
		}
	}
	exits(ret);
}

char*
canon(Biobuf *bp, char *header, char *body, int *n)
{
	int hsize, base64;

	static char *raw;

	hsize = 0;
	base64 = 0;
	*header = 0;
	*body = 0;
	if(raw == 0){
		raw = readmsg(bp, &hsize, n);
		if(raw)
			base64 = convert(raw, raw+hsize, header, Hdrsize, 0);
	} else {
		free(raw);
		raw = readmsg(bp, 0, n);
	}
	if(raw){
		if(base64)
			conv64(raw+hsize, raw+*n, body, Bodysize);
		else
			convert(raw+hsize, raw+*n, body, Bodysize, 1);
	}
	return raw;
}

int
matchaction(Patterns *pp, char *message)
{
	char *name, *cp;
	int ret;
	Pattern *p;
	Resub m[1];

	if(message == 0 || *message == 0)
		return 0;

	name = pp->action;
	p = pp->strings;
	ret = 0;
	if(p)
		for(cp = message; matcher(name, p, cp, m); cp = m[0].ep)
				ret++;

	for(p = pp->regexps; p; p = p->next)
		for(cp = message; matcher(name, p, cp, m); cp = m[0].ep)
				ret++;
	return ret;
}

int
matcher(char *action, Pattern *p, char *message, Resub *m)
{
	if(matchpat(p, message, m)){
		if(p->action != Lineoff)
			xprint(1, action, m);
		return 1;
	}
	return 0;
}
