/* scanjmsg interfaces with the HOLD_PARSER option  of Jnos under Unix:
 *   #define HOLD_PARSER  "/path/to/scanjmsg"
 * which will, when 'mbox holdlocal yes' is in effect, call this program
 * for each smtp msg processed.  The complete msg is passed to stdin, and
 * stdout will display on the console (typically syntax errors).  The return
 * code will determine if the msg is held: 0 for no, non-zero for yes.
 * Each msg line is compared against regular expressions (see man regcomp)
 * obtained from SCANFILE.  Regular expressions found before an empty line
 * are applied to the msg headers.  Expressions afterward are applied to
 * the msg body.  A match will result in the msg being held.
 *
 * Note no msg header line is added to indicate a held msg; just the Jnos
 * area index is flagged.
 * A Perl program could probably do this job, too, but it appears that
 * stdin must be rewound by this program to have the Jnos parent be able
 * to process the msg normally (in Linux 2.0.33/RedHat 5.0, anyhow).
 *
 * Syntax:  scanjmsg [-m] [-f regexpr_file]
 * where -m        => do NOT translate to lower case before scanning the msg.
 *	 -f path   => use path as the regular expressions file.
 *
 * -- James Dugal, N5KNX  19 Sep 1998
 * Compile by: gcc -o scanjmsg scanjmsg.c
 */

#include <stdio.h>
#include <string.h>
#include <regex.h>
#include "getopt.h"

#ifndef SCANFILE
#define SCANFILE	"/home/jpd/jnos/scanjmsg.dat"
#endif

#define NULLS (char *)NULL

#define HOLD 1
#define RELEASE 0

static char *
strlwr(s)
    char *s;
{
    register char *p = s;

    while (*p)
        *p = tolower(*p), p++;
    return s;
}

int main(int argc, char *argv[])
{
    char buf[BUFSIZ], ebuf[BUFSIZ];
    int  retcode = RELEASE;
    int  translower=REG_ICASE;
    int  in_msg_header=1, in_header_exprs=1, complain=1;
    int  c;
    char *expfile = SCANFILE;
    FILE *Efile;
    long Efilepos;

    while((c = getopt(argc,argv,"mf:")) != EOF){
        switch(c){
	case 'm':       /* retain mixed case before analysis */
	  translower=0;
	  break;
	case 'f':
	  expfile = optarg;
	  break;
	}
    }

    if ((Efile = fopen(expfile, "r")) == NULL) {
      perror(expfile);
      return RELEASE;
    }
    Efilepos = ftell(Efile);

    while (fgets(buf, sizeof buf, stdin) != NULL) {
        regex_t iform;
	int i;

        /*if (translower) (void)strlwr(buf);*//* see REG_ICASE, below */
	if (in_msg_header && *buf == '\n') {
	  in_msg_header=0;
	  while(in_header_exprs) {
	    if (fgets(ebuf, sizeof ebuf, Efile) == NULL)
	      goto fin1;
	    if (*ebuf == '\n') in_header_exprs = 0;
	  }
	  Efilepos = ftell(Efile);
	  continue;
	}
	if (buf[strlen(buf)-1] == '\n')
	  buf[strlen(buf)-1] = '\0';
	else
	  fprintf(stderr,"Long msg line %s truncated\n", buf);

	if(fseek(Efile, Efilepos, SEEK_SET) != 0) {
	  perror(expfile);
	  goto fin1;
	}
	while (1) {
	  if (fgets(ebuf, sizeof ebuf, Efile) == NULL)
	    break;
	  if (in_header_exprs && *ebuf == '\n') {
	    break;
	  }

	  if (ebuf[strlen(ebuf)-1] == '\n')
	    ebuf[strlen(ebuf)-1] = '\0';
	  else
	    fprintf(stderr,"Long expression %s truncated\n", ebuf);

          if ((i=regcomp(&iform, ebuf, translower|REG_NOSUB|REG_EXTENDED)) != 0) {
	    if (complain) {
	      regerror(i,&iform, ebuf, sizeof(ebuf));
	      fprintf(stderr, "%s\n", ebuf);
	    }
	    continue;
	  }
	  if (regexec(&iform, buf, 0, NULL, 0) == 0) {
	    regfree(&iform);
	    retcode = HOLD;
	    goto  fin1;
	  }
	  else regfree(&iform);  /* no match */
	} /* end while(1) */
	if (!in_header_exprs) complain=0;  /* don't duplicate complaints */
    } /* end while(fgets...stdin) */
 fin1:
    fclose(Efile);
    rewind(stdin);   /* try to help parent start over */
    exit (retcode);
}

