/*
  groupcheck.c
  written by Olaf Titz, July 1997 as part of c-nocem.
  Public domain.

  Reads pattern file (e.g. GUP format) from specified file.
  Then reads lines from stdin: <mid> group group...

  Prints IDs for which at least one group matches the pattern file.
  With CANCELFEED defined, send them directly to a cancel channel instead.

*/
static char *RCSID="$Id: groupcheck.c,v 1.5 2000/05/23 09:39:01 olaf Exp $";

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>

#if 1
#include "configdata.h"
#include "clibrary.h"
#include "libinn.h"
#else
extern int ReadInnConf(void);
extern int wildmat(const char *text, const char *pattern);
extern int NNTPlocalopen(FILE **FromServerp, FILE **ToServerp, char *errbuff);
#endif

#define MAXLINE 10000
#define MAXNPAT 10000

#ifdef CANCELFEED
static FILE *cmd, *resp;                /* Command/response channels */
#endif

static time_t starttime;
static int sproc=0, scncl=0, serr=0;     /* statistics */

static void usage(const char *p)
{
    fprintf(stderr, "usage: %s patfile\n", p);
    exit(1);
    /* NOTREACHED */
}

#ifdef __GNUC__
static void statexit(int n) __attribute__((__noreturn__));
#endif

static void statexit(int n)
{
#ifdef CANCELFEED
    openlog("cancelfeed", L_OPENLOG_FLAGS|LOG_PID, LOG_INN_PROG);
    syslog(L_NOTICE, "time %ld processed %d cancelled %d errors %d\n",
           time(0)-starttime, sproc, scncl, serr);
#endif
    exit(n);
}

#ifdef CANCELFEED
static char *fgetsr(char *s, int size, FILE *stream)
{
    register char *x=fgets(s, size, stream);
    if (!x)
        return NULL;
    while (*x) {
        if (*x=='\r') {
            *x='\0';
            return s;
        }
        x++;
    }
    return s;
}
#endif

static char *ptns[MAXNPAT];
static int nptns=0;

static void read_pat(const char *f)
{
    struct stat st;
    char *p;
    int a=open(f, O_RDONLY);
    if (a<0) {
        nptns=-1; return;
    }
    if (fstat(a, &st)<0) {
	perror("fstat"); exit(1);
    }
    if (st.st_size<1) {
        nptns=-1; return;
    }
    if (!(p=malloc(st.st_size+1))) {
	perror("malloc"); exit(1);
    }
    memset(p, 0, st.st_size+1);
    if (read(a, p, st.st_size)!=st.st_size) {
	perror("read/short"); exit(1);
    }
    close(a);
    if (st.st_size>0) {
	(void) strtok(p, " \t\n,");
	do {
	    ptns[nptns++]=p;
	    if (nptns>=MAXNPAT) {
		fprintf(stderr, "Too many patterns in %s\n", f);
		exit(1);
	    }
	} while ((p=strtok(NULL, " \t\n,")));
    }
    --nptns;
}

static int do_match(char *g)
{
    char *p;
    int i, m;

    for (i=nptns; i>=0; --i) {
	p=ptns[i];
	if (*p=='!') {
	    ++p; m=0;
	} else {
	    m=1;
	}
	if (wildmat(g, p))
	    return m;
    }
    return 0;
}

static void do_line(char *lin)
{
    char *p;

    /* skip ID */
    (void) strtok(lin, " \t\n");
    while ((p=strtok(NULL, "\t \n"))) {
	if (nptns<0 || do_match(p)) {
#ifdef CANCELFEED
            char buf[128];
	    fputs(lin, cmd);
            fputs("\r\n", cmd);
            fflush(cmd);
            if (!fgetsr(buf, sizeof(buf), resp)) {
                fprintf(stderr, "server closed connection\n");
                statexit(0);
            }
            if (strncmp(buf, "289", 3)) {
                fprintf(stderr, "%s\n", buf);
                ++serr;
            } else
                ++scncl;
#else
	    fputs(lin, stdout);
	    fputc('\n', stdout);
#endif
	    return;
	}
    }
}

int main(int argc, char *argv[])
{
    char buf[MAXLINE];
    int c0, c1=1;

    if (argc!=2)
	usage(argv[0]);
    read_pat(argv[1]);

#ifdef CANCELFEED
    if (ReadInnConf() < 0) exit(1);
    if (NNTPlocalopen(&resp, &cmd, buf)<0) {
        fprintf(stderr, "connect: %s\n", buf);
        exit(1);
    }
    fprintf(cmd, "MODE CANCEL\r\n");
    fflush(cmd);
    if (!fgetsr(buf, sizeof(buf), resp)) {
        fprintf(stderr, "MODE: close\n");
        exit(1);
    }
    if (strncmp(buf, "284", 3)) {
        fprintf(stderr, "MODE: %s\n", buf);
        exit(1);
    }
#endif
    starttime=time(0);
    while (fgets(buf, sizeof(buf), stdin)) {
	c0=c1;
	c1=(buf[strlen(buf)-1]=='\n');
	if (!c0)
	    continue; /* skip continuation bogosities */
	if (!c1) {
	    fprintf(stderr, "stdin: long line\n");
            ++serr;
	    continue;
	}
	do_line(buf);
        ++sproc;
    }
    statexit(0);
}
