/*$Id: ezmlm-limit.c,v 1.2 1999/10/31 18:58:48 lindberg Exp $*/
/*$Name: ezmlm-idx-040 $*/

#include <sys/types.h>
#include "stralloc.h"
#include "substdio.h"
#include "readwrite.h"
#include "strerr.h"
#include "sig.h"
#include "lock.h"
#include "getconf.h"
#include "fmt.h"
#include "now.h"
#include "sgetopt.h"
#include "error.h"
#include "errtxt.h"
#include "idx.h"

#define FATAL "ezmlm-limit: fatal: "
#define INFO "ezmlm-limit: info: "

unsigned long deltasecs = LIMSECS;	/* interval to test over (seconds) */
unsigned long deltanum = LIMMSG;	/* max no messages in interval */
					/* see idx.h. Usually 30 msg/3600 secs*/
int flagd = 0;				/* =0 create modpost, =1 ignore */
					/* excess, =2 defer excess */
int flagmod;				/* list moderated */
int flagloop;
char *fn = TXT_LOOPNUM;

void die_usage()
{
  strerr_die1x(100,
	"ezmlm-limit: usage: ezmlm-limit [-f file] [-dDF] [-n messages]"
	" [-t secs] dir");
}

void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }

void die_new() { strerr_die4sys(111,FATAL,ERR_WRITE,fn,": "); }

stralloc line = {0};

substdio ssnew;
char newbuf[16];

char strnum[FMT_ULONG];

void main(argc,argv)
int argc;
char **argv;
{
  char *dir;
  int opt;
  unsigned int pos;
  unsigned long num, loopnum, when;
  unsigned long loopwhen = 0L;
  unsigned long numwhen = 0L;
  int fd,fdlock;

  (void) umask(022);
  sig_pipeignore();
  when = (unsigned long) now();

  while ((opt = getopt(argc,argv,"dDf:Fn:t:")) != opteof)
    switch(opt) {
      case 'd': flagd = 1; break;
      case 'D': flagd = 0; break;
      case 'f': if (optarg && *optarg) fn = optarg; break;
      case 'F': fn = TXT_LOOPNUM;
      case 'n':
                if (optarg)
                  scan_ulong(optarg,&deltanum);
                break;
      case 't':
                if (optarg)
                  scan_ulong(optarg,&deltasecs);
                break;
      default:
	die_usage();
  }

  dir = argv[optind++];
  if (!dir) die_usage();

  if (chdir(dir) == -1)
    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");

  if (argv[optind])
    die_usage();	/* avoid common error of putting options after dir */
  if ((flagmod = getconf_line(&line,"modpost",0,FATAL,dir)))
    _exit(0);		/* already mod */
			/* lock for num and for writing loopnum */
  fdlock = open_append("lock");
  if (fdlock == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/lock: ");
  if (lock_ex(fdlock) == -1)
    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/lock: ");

  if (!getconf_line(&line,"num",0,FATAL,dir))
    _exit(99);						/* no msgs */
  if(!stralloc_0(&line)) die_nomem();
  pos = scan_ulong(line.s,&num);			/* current msg */
  if ((flagloop = getconf_line(&line,fn,0,FATAL,dir))) {
    if(!stralloc_0(&line)) die_nomem();
    pos = scan_ulong(line.s,&loopnum);			/* msg when written */
    if (line.s[pos] == ':')
      scan_ulong(line.s+pos+1,&loopwhen);		/* time written */
  }
  if (!flagloop || loopwhen + deltasecs < when || loopwhen > when) {
					/* loopnum too old, bad or not there */
      fd = open_trunc(fn);		/* no need to write crash-proof */
      if (fd == -1) die_new();
      substdio_fdbuf(&ssnew,write,fd,newbuf,sizeof(newbuf));
      if (substdio_put(&ssnew,strnum,fmt_ulong(strnum,num)) == -1) die_new();
      if (substdio_puts(&ssnew,":") == -1) die_new();
      if (substdio_put(&ssnew,strnum,fmt_ulong(strnum,when)) == -1) die_new();
      if (substdio_puts(&ssnew,"\n") == -1) die_new();
      if (substdio_flush(&ssnew) == -1) die_new();
      close(fd);
  } else if (num >= loopnum + deltanum) {	/* excess messages */
    if (!flagd) {
      if ((fd = open_append("modpost")) == -1)	/* create dir/modpost */
	  strerr_die3sys(111,FATAL,ERR_WRITE,"subpost:");
      else {
        close(fd);
        unlink(fn);
        strerr_die2x(0,INFO,ERR_EXCESS_MOD);
      }
    } else
        strerr_die2x(111,FATAL,ERR_EXCESS_DEFER);
  }
  _exit(0);
}
