summaryrefslogtreecommitdiff
path: root/src/setforward.c
diff options
context:
space:
mode:
authorJannis Hoffmann <jannis@fehcom.de>2024-07-03 15:48:04 +0200
committerJannis Hoffmann <jannis@fehcom.de>2024-07-03 15:48:04 +0200
commit89b7b67a13ebb7965cc7f13ad0595e2194a2d34c (patch)
tree25efd77a90ae87236e6730d8ea3846bbe0fd126f /src/setforward.c
add sqmail-4.2.29asqmail-4.2
Diffstat (limited to 'src/setforward.c')
-rw-r--r--src/setforward.c173
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);
+}