summaryrefslogtreecommitdiff
path: root/src/matchup.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/matchup.c
add sqmail-4.2.29asqmail-4.2
Diffstat (limited to 'src/matchup.c')
-rw-r--r--src/matchup.c489
1 files changed, 489 insertions, 0 deletions
diff --git a/src/matchup.c b/src/matchup.c
new file mode 100644
index 0000000..047ea65
--- /dev/null
+++ b/src/matchup.c
@@ -0,0 +1,489 @@
+#include <unistd.h>
+#include "genalloc.h"
+#include "alloc.h"
+#include "stralloc.h"
+#include "logmsg.h"
+#include "getln.h"
+#include "buffer.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "str.h"
+#include "fmt.h"
+#include "scan.h"
+#include "case.h"
+
+#define WHO "matchup"
+
+void nomem() { logmsg(WHO,111,FATAL,"out of memory"); }
+void die_read() { logmsg(WHO,110,ERROR,"unable to read input: "); }
+void die_write() { logmsg(WHO,110,ERROR,"unable to write output: "); }
+void die_write5() { logmsg(WHO,111,FATAL,"unable to write fd 5: "); }
+
+void out(char *buf,int len)
+{
+ if (buffer_put(buffer_1,buf,len) == -1) die_write();
+}
+void outs(char *buf)
+{
+ if (buffer_puts(buffer_1,buf) == -1) die_write();
+}
+
+char buf5[512];
+buffer bo5 = BUFFER_INIT(write,5,buf5,sizeof(buf5));
+
+void out5(char *buf,int len)
+{
+ if (buffer_put(&bo5,buf,len) == -1)
+ die_write5();
+}
+void outs5(char *buf)
+{
+ if (buffer_puts(&bo5,buf) == -1)
+ die_write5();
+}
+
+GEN_ALLOC_typedef(ulongalloc,unsigned long,u,len,a)
+GEN_ALLOC_ready(ulongalloc,unsigned long,u,len,a,i,n,x,30,ulongalloc_ready)
+GEN_ALLOC_readyplus(ulongalloc,unsigned long,u,len,a,i,n,x,30,ulongalloc_readyplus)
+
+char strnum[FMT_ULONG];
+
+stralloc pool = {0};
+unsigned int poolbytes = 0;
+
+int nummsg = 0;
+ulongalloc msg = {0};
+ulongalloc bytes = {0};
+ulongalloc qp = {0};
+ulongalloc uid = {0};
+ulongalloc numk = {0};
+ulongalloc numd = {0};
+ulongalloc numz = {0};
+ulongalloc sender = {0};
+ulongalloc birth = {0};
+
+int msg_find(unsigned long m)
+{
+ int i;
+ for (i = 0; i < nummsg; ++i)
+ if (msg.u[i] == m) return i;
+ return -1;
+}
+
+int msg_add(unsigned long m)
+{
+ int i;
+ for (i = 0; i < nummsg; ++i)
+ if (msg.u[i] == m) return i;
+ i = nummsg++;
+ if (!ulongalloc_ready(&msg,nummsg)) nomem();
+ if (!ulongalloc_ready(&bytes,nummsg)) nomem();
+ if (!ulongalloc_ready(&qp,nummsg)) nomem();
+ if (!ulongalloc_ready(&uid,nummsg)) nomem();
+ if (!ulongalloc_ready(&numk,nummsg)) nomem();
+ if (!ulongalloc_ready(&numd,nummsg)) nomem();
+ if (!ulongalloc_ready(&numz,nummsg)) nomem();
+ if (!ulongalloc_ready(&sender,nummsg)) nomem();
+ if (!ulongalloc_ready(&birth,nummsg)) nomem();
+ msg.u[i] = m;
+ return i;
+}
+
+void msg_kill(int i)
+{
+ poolbytes -= str_len(pool.s + sender.u[i]) + 1;
+ poolbytes -= str_len(pool.s + birth.u[i]) + 1;
+
+ --nummsg;
+ msg.u[i] = msg.u[nummsg];
+ bytes.u[i] = bytes.u[nummsg];
+ qp.u[i] = qp.u[nummsg];
+ uid.u[i] = uid.u[nummsg];
+ numk.u[i] = numk.u[nummsg];
+ numd.u[i] = numd.u[nummsg];
+ numz.u[i] = numz.u[nummsg];
+ sender.u[i] = sender.u[nummsg];
+ birth.u[i] = birth.u[nummsg];
+}
+
+int numdel = 0;
+ulongalloc del = {0};
+ulongalloc dmsg = {0};
+ulongalloc dchan = {0};
+ulongalloc drecip = {0};
+ulongalloc dstart = {0};
+
+int del_find(unsigned long d)
+{
+ int i;
+ for (i = 0; i < numdel; ++i)
+ if (del.u[i] == d) return i;
+ return -1;
+}
+
+int del_add(unsigned long d)
+{
+ int i;
+ for (i = 0; i < numdel; ++i)
+ if (del.u[i] == d) return i;
+ i = numdel++;
+ if (!ulongalloc_ready(&del,numdel)) nomem();
+ if (!ulongalloc_ready(&dmsg,numdel)) nomem();
+ if (!ulongalloc_ready(&dchan,numdel)) nomem();
+ if (!ulongalloc_ready(&drecip,numdel)) nomem();
+ if (!ulongalloc_ready(&dstart,numdel)) nomem();
+ del.u[i] = d;
+ return i;
+}
+
+void del_kill(int i)
+{
+ poolbytes -= str_len(pool.s + dchan.u[i]) + 1;
+ poolbytes -= str_len(pool.s + drecip.u[i]) + 1;
+ poolbytes -= str_len(pool.s + dstart.u[i]) + 1;
+ --numdel;
+ del.u[i] = del.u[numdel];
+ dmsg.u[i] = dmsg.u[numdel];
+ dchan.u[i] = dchan.u[numdel];
+ drecip.u[i] = drecip.u[numdel];
+ dstart.u[i] = dstart.u[numdel];
+}
+
+stralloc pool2 = {0};
+
+void garbage()
+{
+ int i;
+ char *x;
+
+ if (pool.len - poolbytes < poolbytes + 4096) return;
+
+ if (!stralloc_copys(&pool2,"")) nomem();
+
+ for (i = 0; i < nummsg; ++i) {
+ x = pool.s + birth.u[i];
+ birth.u[i] = pool2.len;
+ if (!stralloc_cats(&pool2,x)) nomem();
+ if (!stralloc_0(&pool2)) nomem();
+ x = pool.s + sender.u[i];
+ sender.u[i] = pool2.len;
+ if (!stralloc_cats(&pool2,x)) nomem();
+ if (!stralloc_0(&pool2)) nomem();
+ }
+
+ for (i = 0; i < numdel; ++i) {
+ x = pool.s + dstart.u[i];
+ dstart.u[i] = pool2.len;
+ if (!stralloc_cats(&pool2,x)) nomem();
+ if (!stralloc_0(&pool2)) nomem();
+ x = pool.s + dchan.u[i];
+ dchan.u[i] = pool2.len;
+ if (!stralloc_cats(&pool2,x)) nomem();
+ if (!stralloc_0(&pool2)) nomem();
+ x = pool.s + drecip.u[i];
+ drecip.u[i] = pool2.len;
+ if (!stralloc_cats(&pool2,x)) nomem();
+ if (!stralloc_0(&pool2)) nomem();
+ }
+
+ if (!stralloc_copy(&pool,&pool2)) nomem();
+
+ poolbytes = pool.len; /* redundant, but doesn't hurt */
+}
+
+stralloc line = {0};
+int match;
+
+#define FIELDS 20
+int field[FIELDS];
+
+void clear()
+{
+ while (numdel > 0)
+ del_kill(0);
+ garbage();
+}
+
+void starting()
+{
+ unsigned long d;
+ unsigned long m;
+ int dpos;
+
+ scan_ulong(line.s + field[3],&d);
+ scan_ulong(line.s + field[5],&m);
+
+ dpos = del_add(d);
+
+ dmsg.u[dpos] = m;
+
+ dstart.u[dpos] = pool.len;
+ if (!stralloc_cats(&pool,line.s + field[0])) nomem();
+ if (!stralloc_0(&pool)) nomem();
+
+ dchan.u[dpos] = pool.len;
+ if (!stralloc_cats(&pool,line.s + field[7])) nomem();
+ if (!stralloc_0(&pool)) nomem();
+
+ drecip.u[dpos] = pool.len;
+ if (!stralloc_cats(&pool,line.s + field[8])) nomem();
+ if (!stralloc_0(&pool)) nomem();
+ case_lowers(pool.s + drecip.u[dpos]);
+
+ poolbytes += pool.len - dstart.u[dpos];
+}
+
+void delivery()
+{
+ unsigned long d;
+ unsigned long m;
+ int dpos;
+ int mpos;
+ char *result = "?";
+ char *reason = "";
+
+ scan_ulong(line.s + field[2],&d);
+
+ dpos = del_find(d);
+ if (dpos == -1) return;
+
+ m = dmsg.u[dpos];
+ mpos = msg_find(m);
+
+ if (str_start(line.s + field[3],"succ")) {
+ if (mpos != -1) ++numk.u[mpos];
+ result = "d k ";
+ reason = line.s + field[4];
+ }
+ else if (str_start(line.s + field[3],"fail")) {
+ if (mpos != -1) ++numd.u[mpos];
+ result = "d d ";
+ reason = line.s + field[4];
+ }
+ else if (str_start(line.s + field[3],"defer")) {
+ if (mpos != -1) ++numz.u[mpos];
+ result = "d z ";
+ reason = line.s + field[4];
+ }
+ else if (str_start(line.s + field[3],"report")) {
+ if (mpos != -1) ++numz.u[mpos];
+ result = "d z ";
+ reason = "report_mangled";
+ }
+
+ outs(result);
+
+ if (mpos != -1) {
+ outs(pool.s + birth.u[mpos]);
+ outs(" "); outs(pool.s + dstart.u[dpos]);
+ outs(" "); outs(line.s + field[0]);
+ outs(" "); out(strnum,fmt_ulong(strnum,bytes.u[mpos]));
+ outs(" "); outs(pool.s + sender.u[mpos]);
+ outs(" "); outs(pool.s + dchan.u[dpos]);
+ outs("."); outs(pool.s + drecip.u[dpos]);
+ outs(" "); out(strnum,fmt_ulong(strnum,qp.u[mpos]));
+ outs(" "); out(strnum,fmt_ulong(strnum,uid.u[mpos]));
+ outs(" "); outs(reason);
+ } else {
+ outs(pool.s + dstart.u[dpos]);
+ outs(" "); outs(pool.s + dstart.u[dpos]);
+ outs(" "); outs(line.s + field[0]);
+ outs(" 0 ? "); outs(pool.s + dchan.u[dpos]);
+ outs("."); outs(pool.s + drecip.u[dpos]);
+ outs(" ? ? "); outs(reason);
+ }
+
+ outs("\n");
+
+ del_kill(dpos);
+ garbage();
+}
+
+void newmsg()
+{
+ unsigned long m;
+ int mpos;
+
+ scan_ulong(line.s + field[3],&m);
+ mpos = msg_find(m);
+ if (mpos == -1) return;
+ msg_kill(mpos);
+ garbage();
+}
+
+void endmsg()
+{
+ unsigned long m;
+ int mpos;
+
+ scan_ulong(line.s + field[3],&m);
+ mpos = msg_find(m);
+ if (mpos == -1) return;
+
+ outs("m "); outs(pool.s + birth.u[mpos]);
+ outs(" "); outs(line.s + field[0]);
+ outs(" "); out(strnum,fmt_ulong(strnum,bytes.u[mpos]));
+ outs(" "); out(strnum,fmt_ulong(strnum,numk.u[mpos]));
+ outs(" "); out(strnum,fmt_ulong(strnum,numd.u[mpos]));
+ outs(" "); out(strnum,fmt_ulong(strnum,numz.u[mpos]));
+ outs(" "); outs(pool.s + sender.u[mpos]);
+ outs(" "); out(strnum,fmt_ulong(strnum,qp.u[mpos]));
+ outs(" "); out(strnum,fmt_ulong(strnum,uid.u[mpos]));
+ outs("\n");
+
+ msg_kill(mpos);
+ garbage();
+}
+
+void info()
+{
+ unsigned long m;
+ int mpos;
+
+ scan_ulong(line.s + field[3],&m);
+ mpos = msg_add(m);
+
+ scan_ulong(line.s + field[5],&bytes.u[mpos]);
+ scan_ulong(line.s + field[9],&qp.u[mpos]);
+ scan_ulong(line.s + field[11],&uid.u[mpos]);
+
+ numk.u[mpos] = 0;
+ numd.u[mpos] = 0;
+ numz.u[mpos] = 0;
+
+ birth.u[mpos] = pool.len;
+ if (!stralloc_cats(&pool,line.s + field[0])) nomem();
+ if (!stralloc_0(&pool)) nomem();
+
+ sender.u[mpos] = pool.len;
+ if (!stralloc_cats(&pool,line.s + field[7])) nomem();
+ if (!stralloc_0(&pool)) nomem();
+ case_lowers(pool.s + sender.u[mpos]);
+
+ poolbytes += pool.len - birth.u[mpos];
+}
+
+void extra()
+{
+ unsigned long m;
+ int mpos;
+
+ scan_ulong(line.s + field[2],&m);
+ mpos = msg_find(m);
+ if (mpos == -1) return;
+
+ scan_ulong(line.s + field[3],&numk.u[mpos]);
+ scan_ulong(line.s + field[4],&numz.u[mpos]);
+ scan_ulong(line.s + field[5],&numd.u[mpos]);
+}
+
+void pending()
+{
+ int i;
+
+ for (i = 0; i < nummsg; ++i) {
+ outs5(pool.s + birth.u[i]);
+ outs5(" info msg ");
+ out5(strnum,fmt_ulong(strnum,msg.u[i]));
+ outs5(": bytes ");
+ out5(strnum,fmt_ulong(strnum,bytes.u[i]));
+ outs5(" from ");
+ outs5(pool.s + sender.u[i]);
+ outs5(" qp ");
+ out5(strnum,fmt_ulong(strnum,qp.u[i]));
+ outs5(" uid ");
+ out5(strnum,fmt_ulong(strnum,uid.u[i]));
+ outs5("\n");
+ outs5(pool.s + birth.u[i]);
+ outs5(" extra ");
+ out5(strnum,fmt_ulong(strnum,msg.u[i]));
+ outs5(" ");
+ out5(strnum,fmt_ulong(strnum,numk.u[i]));
+ outs5(" ");
+ out5(strnum,fmt_ulong(strnum,numz.u[i]));
+ outs5(" ");
+ out5(strnum,fmt_ulong(strnum,numd.u[i]));
+ outs5("\n");
+ }
+
+ for (i = 0; i < numdel; ++i) {
+ outs5(pool.s + dstart.u[i]);
+ outs5(" starting delivery ");
+ out5(strnum,fmt_ulong(strnum,del.u[i]));
+ outs5(": msg ");
+ out5(strnum,fmt_ulong(strnum,dmsg.u[i]));
+ outs5(" to ");
+ outs5(pool.s + dchan.u[i]);
+ outs5(" ");
+ outs5(pool.s + drecip.u[i]);
+ outs5("\n");
+ }
+
+ out5(line.s,line.len);
+ if (buffer_flush(&bo5) == -1) die_write5();
+}
+
+stralloc outline = {0};
+
+int main()
+{
+ int i;
+ int j;
+ char ch;
+
+ if (!stralloc_copys(&pool,"")) nomem();
+
+ if (!ulongalloc_ready(&msg,1)) nomem();
+ if (!ulongalloc_ready(&bytes,1)) nomem();
+ if (!ulongalloc_ready(&qp,1)) nomem();
+ if (!ulongalloc_ready(&uid,1)) nomem();
+ if (!ulongalloc_ready(&numk,1)) nomem();
+ if (!ulongalloc_ready(&numd,1)) nomem();
+ if (!ulongalloc_ready(&numz,1)) nomem();
+ if (!ulongalloc_ready(&del,1)) nomem();
+ if (!ulongalloc_ready(&dmsg,1)) nomem();
+
+ for (;;) {
+ if (getln(buffer_0,&line,&match,'\n') == -1) die_read();
+ if (!match) break;
+
+ if (!stralloc_copy(&outline,&line)) nomem();
+
+ for (i = 0; i < line.len; ++i) {
+ ch = line.s[i];
+ if ((ch == '\n') || (ch == ' ') || (ch == '\t')) line.s[i] = 0;
+ }
+ j = 0;
+ for (i = 0; i < FIELDS; ++i) {
+ while (j < line.len) if (line.s[j]) break; else ++j;
+ field[i] = j;
+ while (j < line.len) if (!line.s[j]) break; else ++j;
+ }
+ if (!stralloc_0(&line)) nomem();
+
+ if (str_equal(line.s + field[1],"status:")) ;
+ else if (str_equal(line.s + field[1],"starting")) starting();
+ else if (str_equal(line.s + field[1],"delivery")) delivery();
+ else if (str_equal(line.s + field[1],"new")) newmsg();
+ else if (str_equal(line.s + field[1],"end")) endmsg();
+ else if (str_equal(line.s + field[1],"info")) info();
+ else if (str_equal(line.s + field[1],"extra")) extra();
+ else if (str_equal(line.s + field[1],"running")) clear();
+ else if (str_equal(line.s + field[1],"exiting")) clear();
+ else if (str_equal(line.s + field[1],"number")) ;
+ else if (str_equal(line.s + field[1],"local")) ;
+ else if (str_equal(line.s + field[1],"remote")) ;
+ else if (str_equal(line.s + field[1],"warning:")) out(outline.s,outline.len);
+ else if (str_equal(line.s + field[1],"alert:")) out(outline.s,outline.len);
+ else {
+ outs("? ");
+ out(outline.s,outline.len);
+ }
+ }
+
+ if (buffer_flush(buffer_1) == -1) die_write();
+
+ pending();
+
+ _exit(0);
+}