/*
     extract - A network log processor
     Copyright (C) 1993 Douglas Lee Schales, David K. Hess, David R. Safford

     Please see the file `COPYING' for the complete copyright notice.

interp.c - 03/20/93

*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include "extract.h"
#include "parser.h"
#include "y.tab.h"
#include "interp.h"

#define CONTINUE 0
#define RETURN 1

static unsigned long evaluate(struct tcpsynout *, struct parsenode *);
static unsigned long checkcond(unsigned long, unsigned long, int);
static int perform(struct tcpsynout *, struct actionlist *);
extern void writebuf(struct tcpsynout *);

static unsigned long rectime = 0;

void
interp(struct tcpsynout *rec, struct parsetree *pt)
{
     struct parsetree *rove;
     int status;

     rectime = 0;
     for(rove = pt;rove;rove=rove->next){
	  if(!rove->conditions || evaluate(rec, rove->conditions)){
	       status = perform(rec, rove->actions);
	       if(status == RETURN)
		    return;
	  }
     }
}

unsigned long
evaluate(struct tcpsynout *rec, struct parsenode *pn)
{
     unsigned long lhs, rhs;
     struct tm *tmb;

     if(pn->nodetype == KEY){
	  switch(pn->nodeval){
	  case SRCADDR:
	  case SRCNET:
	       return rec->ipsrcaddr;
	       break;
	  case DSTADDR:
	  case DSTNET:
	       return rec->ipdstaddr;
	       break;
	  case SRCPORT:
	       return rec->tcpsrcport;
	       break;
	  case DSTPORT:
	       return rec->tcpdstport;
	       break;
	  case DATE:
	       return rec->tp.tv_sec;
	       break;
	  case TIME:
	       if(!rectime){
		    tmb = localtime(&rec->tp.tv_sec);
		    rectime = tmb->tm_hour*3600 + tmb->tm_min*60 + tmb->tm_sec;
	       }
	       return rectime;
	       break;
	  default:
	       /* hmmmm... */
	       break;
	  }
     }
     else if(pn->nodetype == VAL)
	  return pn->nodeval;
     else if(pn->nodetype == UOPER){
	  rhs = evaluate(rec, pn->rhs);
	  switch(pn->nodeval){
	  case '!':
	       return !rhs;
	       break;
	  default:
	       break;
	  }
     }
     else {
	  switch(pn->nodeval){
	  case OR:
	       if((lhs = evaluate(rec, pn->lhs)))
		    return lhs;
	       else
		    return evaluate(rec, pn->rhs);
	       break;
	  case AND:
	       if(!(lhs = evaluate(rec, pn->lhs)))
		    return lhs;
	       else
		    return evaluate(rec, pn->rhs);
	       break;
	  case MASKOPER:
	  case '&':
	       lhs = evaluate(rec, pn->lhs);
	       rhs = evaluate(rec, pn->rhs);
	       return lhs & rhs;
	       break;
	  default:
	       lhs = evaluate(rec, pn->lhs);
	       rhs = evaluate(rec, pn->rhs);
	       return checkcond(lhs, rhs, pn->nodeval);
	  }
     }
     return 0;
}
     
unsigned long
checkcond(unsigned long lhs, unsigned long rhs, int cond)
{
     switch(cond){
     case '=':
	  return lhs == rhs;
	  break;
     case '>':
	  return lhs > rhs;
	  break;
     case '<':
	  return lhs < rhs;
	  break;
     case NEQ:
	  return lhs != rhs;
	  break;
     case LEQ:
	  return lhs <= rhs;
	  break;
     case GEQ:
	  return lhs >= rhs;
	  break;
     }
     return 0;
}

int
perform(struct tcpsynout *rec, struct actionlist *al)
{
     int topaction = CONTINUE;
     struct actionlist *rove;

     for(rove=al;topaction != RETURN && rove;rove=rove->next)
	  switch(rove->action){
	  case PRINT:
	       writebuf(rec);
	       break;
	  case NEXT:
	       topaction = RETURN;
	       break;
	  default:
	       /* Hmmmm */
	       break;
	  }

     return topaction;
}

