#include "strerr.h"
#include "stralloc.h"
#include "substdio.h"
#include "getln.h"
#include "error.h"
#include "exit.h"
#include "readwrite.h"
#include "open.h"
#include "auto_qmail.h"
#include "cdbmss.h"
#include "fmt.h"
#include "scan.h"
#include "byte.h"

#define FATAL "qmail-mfrules: fatal: "

stralloc address = {0};
stralloc data = {0};
stralloc key = {0};
stralloc line = {0};

char inbuf[1024];
substdio ssin;

int fd;
int fdtemp;
int match = 1;

struct cdbmss cdbmss;

void die_nomem(void)
{
  strerr_die2x(112,FATAL,"out of memory");
}
void die_parse(void)
{
  if (!stralloc_0(&line)) die_nomem();
  strerr_die3x(100,FATAL,"unable to parse this line: ",line.s);
}
void die_read()
{
  strerr_die2sys(111,FATAL,"unable to read control/mailfromrules: ");
}
void die_write()
{
  strerr_die2sys(111,FATAL,"unable to write to control/mailfromrules.tmp: ");
}

char strnum[FMT_ULONG];
stralloc sanum = {0};

void getnum(char *buf,int len,unsigned long *u)
{
  if (!stralloc_copyb(&sanum,buf,len)) die_nomem();
  if (!stralloc_0(&sanum)) die_nomem();
  if (sanum.s[scan_ulong(sanum.s,u)]) die_parse();
}

void doaddressdata(void)
{
  int i;
  int left;
  int right;
  unsigned long bot;
  unsigned long top;

  if (byte_chr(address.s,address.len,'=') == address.len)
    if (byte_chr(address.s,address.len,'@') == address.len) {
      i = byte_chr(address.s,address.len,'-');
      if (i < address.len) {
        left = byte_rchr(address.s,i,'.');
        if (left == i) left = 0; else ++left;
  
        ++i;
        right = i + byte_chr(address.s + i,address.len - i,'.');
  
        getnum(address.s + left,i - 1 - left,&bot);
        getnum(address.s + i,right - i,&top);
        if (top > 255) top = 255;
  
        while (bot <= top) {
	  if (!stralloc_copyb(&key,address.s,left)) die_nomem();
	  if (!stralloc_catb(&key,strnum,fmt_ulong(strnum,bot))) die_nomem();
	  if (!stralloc_catb(&key,address.s + right,address.len - right)) die_nomem();
          case_lowerb(key.s,key.len);
          if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_write();
	  ++bot;
        }
  
        return;
      }
    }

  case_lowerb(address.s,address.len);
  case_lowerb(data.s,data.len);
  if (cdbmss_add(&cdbmss,address.s,address.len,data.s,data.len) == -1) die_write();
}

void main()
{
  int colon;
  int dot;
  int i;
  int len;
  char *x;
  char ch;

  umask(033);
  if (chdir(auto_qmail) == -1)
    strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");

  fd = open_read("control/mailfromrules");
  if (fd == -1) die_read();

  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf);

  fdtemp = open_trunc("control/mailfromrules.tmp");
  if (fdtemp == -1) die_write();

  if (cdbmss_start(&cdbmss,fdtemp) == -1) die_write();

  while (match) {
    if (getln(&ssin,&line,&match,'\n') != 0) die_read();

    x = line.s; len = line.len;

    if (!len) break;
    if (x[0] == '#') continue;
    if (x[0] == '\n') continue;

    while (len) {
      ch = x[len - 1];
      if (ch != '\n') if (ch != ' ') if (ch != '\t') break;
      --len;
    }
    line.len = len; /* for die_parse() */

    colon = byte_chr(x,len,':');
    if (!colon) die_parse();
    if (colon) if (colon == len || colon <  2) die_parse();

    dot = byte_chr(x,len,'.');
    if (!dot) die_parse();
    if (dot) if (dot == len) die_parse();

    if (!stralloc_copyb(&address,x,colon)) die_nomem();
    if (!stralloc_copys(&data,"")) die_nomem();

    x = line.s + colon + 1; len = line.len - colon - 1;

    while (len) {
      if (len < 3) die_parse();					/* input checks */
      if ( *x == ',' || *x == ' ' || *x == '\t') die_parse();
      i = byte_chr(x,len,',');
      if (i > 0 && i < len) {
        if (!stralloc_catb(&data,"+",1)) die_nomem();
        if (!stralloc_catb(&data,x,i)) die_nomem(); 
        x += i + 1; len -= i + 1; }
      else {
        if (!stralloc_catb(&data,"+",1)) die_nomem();
        if (!stralloc_catb(&data,x,len)) die_nomem(); 
        len = 0; }
    }
          
    doaddressdata();
  }

  if (cdbmss_finish(&cdbmss) == -1) die_write();
  if (fsync(fdtemp) == -1) die_write();
  if (close(fdtemp) == -1) die_write(); /* NFS stupidity */
  if (rename("control/mailfromrules.tmp","control/mailfromrules.cdb") == -1)
    strerr_die2sys(111,FATAL,"unable to move control/mailfromrules.tmp to control/mailfromrules.cdb");

  _exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1