diff options
author | Jannis Hoffmann <jannis@fehcom.de> | 2024-07-03 15:48:04 +0200 |
---|---|---|
committer | Jannis Hoffmann <jannis@fehcom.de> | 2024-07-03 15:48:04 +0200 |
commit | 89b7b67a13ebb7965cc7f13ad0595e2194a2d34c (patch) | |
tree | 25efd77a90ae87236e6730d8ea3846bbe0fd126f /src/setforward.c |
add sqmail-4.2.29asqmail-4.2
Diffstat (limited to 'src/setforward.c')
-rw-r--r-- | src/setforward.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/setforward.c b/src/setforward.c new file mode 100644 index 0000000..fe17f74 --- /dev/null +++ b/src/setforward.c @@ -0,0 +1,173 @@ +#include <unistd.h> +#include "buffer.h" +#include "logmsg.h" +#include "stralloc.h" +#include "open.h" +#include "case.h" +#include "cdbmake.h" +#include "logmsg.h" + +#define WHO "setforward" + +int rename(const char *,const char *); // stdio.h + +void usage() +{ + logmsg(WHO,100,USAGE,"setforward data.cdb data.tmp"); +} +void nomem() +{ + logmsg(WHO,111,FATAL,"out of memory"); +} +void missingsemicolon() +{ + logmsg(WHO,100,FATAL,"final instruction must end with semicolon"); +} +void extracolon() +{ + logmsg(WHO,100,FATAL,"double colons are not permitted"); +} +void extracomma() +{ + logmsg(WHO,100,FATAL,"commas are not permitted before colons"); +} +void nulbyte() +{ + logmsg(WHO,100,FATAL,"NUL bytes are not permitted"); +} +void longaddress() +{ + logmsg(WHO,100,FATAL,"addresses over 800 bytes are not permitted"); +} + +char *fncdb; +char *fntmp; +int fd; +struct cdb_make cdb; +stralloc key = {0}; + +stralloc target = {0}; /* always initialized; no NUL */ +stralloc command = {0}; /* always initialized; no NUL */ +stralloc instr = {0}; /* always initialized */ + +int flagtarget = 0; +/* 0: reading target; command is empty; instr is empty */ +/* 1: target is complete; instr still has to be written; reading command */ + +void writeerr() +{ + logmsg(WHO,111,FATAL,B("unable to write to: ",fntmp)); +} + +void doit(prepend,data,datalen) +char *prepend; +char *data; +int datalen; +{ + if (!stralloc_copys(&key,prepend)) nomem(); + if (!stralloc_cat(&key,&target)) nomem(); + case_lowerb(key.s,key.len); + if (cdb_make_add(&cdb,key.s,key.len,data,datalen) == -1) + writeerr(); +} + +int getch(ch) +char *ch; +{ + int r; + + r = buffer_get(buffer_0small,ch,1); + if (r == -1) + logmsg(WHO,111,FATAL,"unable to read input: "); + return r; +} + +int main(int argc, char **argv) +{ + char ch; + + if (!stralloc_copys(&target,"")) nomem(); + if (!stralloc_copys(&command,"")) nomem(); + if (!stralloc_copys(&instr,"")) nomem(); + + fncdb = argv[1]; if (!fncdb) usage(); + fntmp = argv[2]; if (!fntmp) usage(); + + fd = open_trunc(fntmp); + if (fd == -1) + logmsg(WHO,111,FATAL,B("unable to create: ",fntmp)); + + if (cdb_make_start(&cdb,fd) == -1) writeerr(); + + for (;;) { + if (!getch(&ch)) goto EOF; + + if (ch == '#') { + while (ch != '\n') if (!getch(&ch)) goto EOF; + continue; + } + + if (ch == ' ') continue; + if (ch == '\n') continue; + if (ch == '\t') continue; + + if (ch == ':') { + if (flagtarget) extracolon(); + flagtarget = 1; + continue; + } + + if ((ch == ',') || (ch == ';')) { + if (!flagtarget) extracomma(); + if (command.len) { + if (command.s[0] == '?') { + doit("?",command.s + 1,command.len - 1); + } + else if ((command.s[0] == '|') || (command.s[0] == '!')) { + if (!stralloc_cat(&instr,&command)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + else if ((command.s[0] == '.') || (command.s[0] == '/')) { + if (!stralloc_cat(&instr,&command)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + else { + if (command.len > 800) longaddress(); + if (command.s[0] != '&') + if (!stralloc_cats(&instr,"&")) nomem(); + if (!stralloc_cat(&instr,&command)) nomem(); + if (!stralloc_0(&instr)) nomem(); + } + } + + if (!stralloc_copys(&command,"")) nomem(); + + if (ch == ';') { + if (instr.len) + doit(":",instr.s,instr.len); + + if (!stralloc_copys(&target,"")) nomem(); + if (!stralloc_copys(&instr,"")) nomem(); + flagtarget = 0; + } + continue; + } + + if (ch == '\\') if (!getch(&ch)) goto EOF; + if (ch == 0) nulbyte(); + if (!stralloc_append(flagtarget ? &command : &target,&ch)) nomem(); + } + + EOF: + if (flagtarget || target.len) + missingsemicolon(); + + if (cdb_make_finish(&cdb) == -1) writeerr(); + if (fsync(fd) == -1) writeerr(); + if (close(fd) == -1) writeerr(); /* NFS stupidity */ + + if (rename(fntmp,fncdb) == -1) + logmsg(WHO,111,FATAL,B("unable to move ",fntmp," to: ",fncdb)); + + _exit(0); +} |