diff options
Diffstat (limited to 'src/qmail-mfrules.c')
-rw-r--r-- | src/qmail-mfrules.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/qmail-mfrules.c b/src/qmail-mfrules.c new file mode 100644 index 0000000..e8cfc94 --- /dev/null +++ b/src/qmail-mfrules.c @@ -0,0 +1,173 @@ +#include <sys/stat.h> +#include <stdio.h> // rename +#include "logmsg.h" +#include "stralloc.h" +#include "buffer.h" +#include "getln.h" +#include "exit.h" +#include <unistd.h> +#include "open.h" +#include "auto_qmail.h" +#include "cdbmake.h" +#include "fmt.h" +#include "scan.h" +#include "byte.h" +#include "case.h" + +#define WHO "qmail-mfrules" + +int rename(const char *,const char *); // stdio.h + +stralloc address = {0}; +stralloc data = {0}; +stralloc key = {0}; +stralloc line = {0}; + +char inbuf[1024]; +buffer bi; + +int fd; +int fdtemp; +int match = 1; + +struct cdb_make cdb; + +void die_nomem() +{ + logmsg(WHO,112,FATAL,"out of memory"); +} +void die_parse() +{ + if (!stralloc_0(&line)) die_nomem(); + logmsg(WHO,100,ERROR,B("unable to parse this line: ",line.s)); +} +void die_read() +{ + logmsg(WHO,111,ERROR,"unable to read control/mailfromrules"); +} +void die_write() +{ + logmsg(WHO,111,ERROR,"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() +{ + 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 (cdb_make_add(&cdb,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 (cdb_make_add(&cdb,address.s,address.len,data.s,data.len) == -1) die_write(); +} + +int main() +{ + int amper; + int i; + int len; + char *x; + char ch; + + umask(033); + if (chdir(auto_qmail) == -1) + logmsg(WHO,111,ERROR,B("unable to chdir to: ",auto_qmail)); + + fd = open_read("control/mailfromrules"); + if (fd == -1) die_read(); + + buffer_init(&bi,read,fd,inbuf,sizeof(inbuf)); + + fdtemp = open_trunc("control/mailfromrules.tmp"); + if (fdtemp == -1) die_write(); + + if (cdb_make_start(&cdb,fdtemp) == -1) die_write(); + + while (match) { + if (getln(&bi,&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() */ + + amper = byte_chr(x,len,'&'); + if (!amper) die_parse(); + if (amper) if (amper == len || amper < 2) die_parse(); + + if (!stralloc_copyb(&address,x,amper)) die_nomem(); + if (!stralloc_copys(&data,"")) die_nomem(); + + x = line.s + amper + 1; len = line.len - amper - 1; + + while (len) { + if (len < 3) die_parse(); /* input checks */ + if ( *x == ',' || *x == ' ' || *x == '\t') die_parse(); + i = byte_chr(x,len,','); /* &addr1,addr2,.. */ + 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 (cdb_make_finish(&cdb) == -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) + logmsg(WHO,111,ERROR,"unable to move control/mailfromrules.tmp to control/mailfromrules.cdb"); + + _exit(0); +} |