/*$Id: ezmlm-tstdig.c,v 1.17 1999/03/20 16:43:42 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 "getconf.h"
#include "env.h"
#include "fmt.h"
#include "now.h"
#include "lock.h"
#include "sgetopt.h"
#include "errtxt.h"
#include "idx.h"

#define FATAL "ezmlm-tstdig: fatal: "

void die_usage()
{
  strerr_die1x(100,"ezmlm-tstdig: usage: ezmlm-tstdig [-k kbytes] [-m messages] [-t hours] dir");
}

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

stralloc line = {0};

substdio ssnum;
char numbuf[16];

char strnum[FMT_ULONG];

int flaglocal = 0;

void main(argc,argv)
int argc;
char **argv;
{
  char *dir;
  char *local;
  char *def;
  int opt;
  unsigned int pos;
  unsigned long num, digsize, dignum;
  unsigned long cumsize = 0L;
  unsigned long deltanum = 0L;
  unsigned long deltawhen = 0L;
  unsigned long deltasize = 0L;
  unsigned long when, tsttime, digwhen;
  int fd,fdlock;

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

  while ((opt = getopt(argc,argv,"k:t:m:vV")) != opteof)
    switch(opt) {
      case 'k':
                if (optarg)
                  scan_ulong(optarg,&deltasize);
                break;
      case 't':
                if (optarg)	/* hours */
                  scan_ulong(optarg,&deltawhen);
                break;
      case 'm':
                if (optarg)
                  scan_ulong(optarg,&deltanum);
                break;
      case 'v':
      case 'V': strerr_die2x(0,"ezmlm-tstdig version: ",EZIDX_VERSION);
      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 (!getconf_line(&line,"num",0,FATAL,dir))
    _exit(99);		/* no msgs no shirt -> no digest */
  if(!stralloc_0(&line)) die_nomem();
  pos = scan_ulong(line.s,&num);
  if (line.s[pos] == ':')
    scan_ulong(line.s+pos+1,&cumsize);

  if (getconf_line(&line,"dignum",0,FATAL,dir)) {
    if(!stralloc_0(&line)) die_nomem();
    pos = scan_ulong(line.s,&dignum);
    if (line.s[pos] == ':')
      pos += 1 + scan_ulong(line.s+pos+1,&digsize);
    if (line.s[pos] == ':')
      scan_ulong(line.s+pos+1,&digwhen);
  } else {
    dignum = 0L;	/* no file, not done any digest */
    digsize = 0L;	/* nothing digested */
    digwhen = 0L;	/* will force a digest, but the last one was eons  */
			/* ago. ezmlm-get sends it out only if there are   */
			/* messages. This is as it should for new lists.   */
  }
  local = env_get("LOCAL");
  if (local && *local) {			/* in editor or manager */
    def = env_get("DEFAULT");
    if (def && *def) {				/* qmail>=1.02 and manager */
      if (!case_starts(def,"dig") || case_starts(def,"digest-"))
        _exit(0);
    } else {				/* older qmail versions or editor */
      if (!getconf_line(&line,"inlocal",0,FATAL,dir)) {
	flaglocal = 1;
      } else {
	pos = str_len(local);
	if (pos <= line.len) {		/* maybe qmail>=1.02 and editor */
	  flaglocal = 1;		/* editor and qmail>=1.02. No harm */
					/* if we're wrong */
	} else {			/* older qmail */
	  if (case_diffb(local,line.len,line.s))	/* local */
	    flaglocal = 1;		/* minimal harm */
          else if (pos < line.len +4 ||	/* in manager and non-digest */
		!case_starts(local+line.len,"-dig"))
	    _exit(0);
          else if (case_starts(local+line.len,"-digest-"))
	    _exit(0);
	}
      }
    }
  }

  if (!deltawhen && !deltasize && !deltanum) _exit(0);
  if ((deltawhen && ((digwhen + deltawhen * 3600L) <= when)) ||
      (deltasize && ((digsize + (deltasize << 2)) <= cumsize)) ||
      (deltanum && ((dignum + deltanum) <= num))) {	/* digest! */
    if (flaglocal) {	/* avoid multiple digests. Of course, ezmlm-tstdig*/
			/* belongs in ezmlm-digest, but it's too late ....*/
      fdlock = open_append("lock");
      if (fdlock == -1)
        strerr_die2sys(111,FATAL,ERR_OPEN_LOCK);
      if (lock_ex(fdlock) == -1) {
        close(fdlock);
        strerr_die2sys(111,FATAL,ERR_OBTAIN_LOCK);
      }
      getconf_line(&line,"tstdig",0,dir,FATAL);
      if (!stralloc_0(&line)) die_nomem();
      scan_ulong(line.s,&tsttime);	/* give digest 1 h to complete */
					/* nobody does digests more often */
      if ((tsttime + 3600L < when) || (tsttime <= digwhen)) {
        fd = open_trunc("tstdign");
        if (fd == -1)
          strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/","tstdign",": ");
        substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf));
        if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,when)) == -1)
          strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/","tstdign",": ");
        if (substdio_puts(&ssnum,"\n") == -1)
          strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/","tstdign",": ");
        if (substdio_flush(&ssnum) == -1)
          strerr_die6sys(111,FATAL,ERR_FLUSH,dir,"/","tstdign",": ");
        if (fsync(fd) == -1)
          strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/","tstdign",": ");
        if (close(fd) == -1)
          strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/","tstdign",": ");
        if (rename("tstdign","tstdig") == -1)
          strerr_die4sys(111,FATAL,ERR_MOVE,"tstdign",": ");
        _exit(0);
      }
    } else
        _exit(0);
  }
  _exit(99);
}

