#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;
}