From: Tomas Zeman <tzeman@volny.cz>
Date: Tue, 6 Nov 2007 11:43:46 +0100
diet-qmailanalog
diff -r e38f008c268e source/dietlibc/diet-qmailanalog/FrugalBuild
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/source/dietlibc/diet-qmailanalog/FrugalBuild Wed Feb 15 15:15:07 2012 +0100
@@ -0,0 +1,37 @@
+# Maintainer: Tomas Zeman <tzeman@volny.cz>
+# Accepts tai64 format dates (lines starting with @....) + mlmatchup
+# see http://www.magma.com.ni/moin/TipsAnd/QmailAnalog
+
+branch=diet
+pkgorig=qmailanalog
+pkgname=$branch-$pkgorig
+pkgver=0.70
+pkgrel=2
+pkgdesc="collection of tools to help you analyze qmail's activity record"
+makedepends=(dietlibc)
+url="http://cr.yp.to/qmailanalog.html"
+archs=(i686)
+up2date='lynx -dump -nolist $url|grep $pkgorig|grep tar.gz|head -1|sed -e "s/.*$pkgorig-\(.*\)\.tar.gz.*$/\1/"'
+source=(http://cr.yp.to/software/$pkgorig-$pkgver.tar.gz \
+ qmailanalog-multilog.patch)
+sha1sums=('d9f47b6c5348759aeba3873b6b7653b823b2f92c' \
+ '05b9b7995e3bef33d8c9c2af239d9d23d95f813f')
+provides=(qmailanalog)
+
+build() {
+ qmail_dir=/var/qmail
+ Fcd $pkgorig-$pkgver
+ echo "$qmail_dir" > conf-home
+ echo "diet gcc $CFLAGS" > conf-cc
+ echo "diet gcc -s -static" > conf-ld
+ Fmkdir $qmail_dir
+ patch -p1 < $Fsrcdir/qmailanalog-multilog.patch || Fdie
+ sed -i -e "s{(auto_home,{(\"$Fdestdir$qmail_dir\",{" hier.c
+ make || Fdie
+ make setup || Fdie
+ Frm $qmail_dir/man/cat*
+ Fmkdir /usr/share/doc/$pkgname-$pkgver
+ Fmv $qmail_dir/doc/* /usr/share/doc/$pkgname-$pkgver
+ Frm $qmail_dir/doc
+}
+# vim: ft=sh
diff -r e38f008c268e source/dietlibc/diet-qmailanalog/qmailanalog-multilog.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/source/dietlibc/diet-qmailanalog/qmailanalog-multilog.patch Wed Feb 15 15:15:07 2012 +0100
@@ -0,0 +1,885 @@
+diff -x .svn -Naur qmailanalog-0.70/error.h qmailanalog/error.h
+--- qmailanalog-0.70/error.h 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/error.h 2007-04-30 20:57:24.000000000 +0200
+@@ -1,7 +1,8 @@
+ #ifndef ERROR_H
+ #define ERROR_H
+
+-extern int errno;
++/* extern int errno; */
++#include <errno.h>
+
+ extern int error_intr;
+ extern int error_nomem;
+diff -x .svn -Naur qmailanalog-0.70/FILES qmailanalog/FILES
+--- qmailanalog-0.70/FILES 1998-08-30 23:39:26.000000000 +0200
++++ qmailanalog/FILES 2007-04-30 20:57:24.000000000 +0200
+@@ -132,3 +132,6 @@
+ case.3
+ case.h
+ case_lowers.c
++mlmatchup.8
++mlmatchup.c
++mlmatchup
+diff -x .svn -Naur qmailanalog-0.70/hier.c qmailanalog/hier.c
+--- qmailanalog-0.70/hier.c 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/hier.c 2007-06-13 11:09:42.000000000 +0200
+@@ -9,12 +9,16 @@
+ d(auto_home,"man",-1,-1,02755);
+ d(auto_home,"man/man1",-1,-1,02755);
+ d(auto_home,"man/cat1",-1,-1,02755);
++ d(auto_home,"man/man8",-1,-1,02755);
++ d(auto_home,"man/cat8",-1,-1,02755);
+
+ c(auto_home,"doc","MATCHUP",-1,-1,0644);
+ c(auto_home,"doc","ACCOUNTING",-1,-1,0644);
+
+ c(auto_home,"man/man1","matchup.1",-1,-1,0644);
+ c(auto_home,"man/cat1","matchup.0",-1,-1,0644);
++ c(auto_home,"man/man8","mlmatchup.8",-1,-1,0644);
++ c(auto_home,"man/cat8","mlmatchup.0",-1,-1,0644);
+ c(auto_home,"man/man1","xqp.1",-1,-1,0644);
+ c(auto_home,"man/cat1","xqp.0",-1,-1,0644);
+ c(auto_home,"man/man1","xsender.1",-1,-1,0644);
+@@ -25,6 +29,7 @@
+ c(auto_home,"man/cat1","columnt.0",-1,-1,0644);
+
+ c(auto_home,"bin","matchup",-1,-1,0755);
++ c(auto_home,"bin","mlmatchup",-1,-1,0755);
+ c(auto_home,"bin","columnt",-1,-1,0755);
+ c(auto_home,"bin","zoverall",-1,-1,0755);
+ c(auto_home,"bin","zsendmail",-1,-1,0755);
+diff -x .svn -Naur qmailanalog-0.70/Makefile qmailanalog/Makefile
+--- qmailanalog-0.70/Makefile 1998-08-30 23:39:26.000000000 +0200
++++ qmailanalog/Makefile 2007-05-03 00:15:12.000000000 +0200
+@@ -243,7 +243,7 @@
+ chmod 755 makelib
+
+ man: \
+-matchup.0 columnt.0 xqp.0 xsender.0 xrecipient.0 alloc.0 case.0 \
++matchup.0 mlmatchup.0 columnt.0 xqp.0 xsender.0 xrecipient.0 alloc.0 case.0 \
+ error.0 error_str.0 getln2.0 getln.0 stralloc.0
+
+ matchup: \
+@@ -275,7 +275,7 @@
+ ./compile open_trunc.c
+
+ prog: \
+-matchup columnt zoverall zsendmail xqp xsender xrecipient ddist \
++matchup mlmatchup columnt zoverall zsendmail xqp xsender xrecipient ddist \
+ deferrals failures successes rhosts recipients rxdelay senders suids \
+ zddist zdeferrals zfailures zsuccesses zrhosts zrecipients zrxdelay \
+ zsenders zsuids
+@@ -566,3 +566,22 @@
+ | sed s}HOME}"`head -1 conf-home`"}g \
+ > zsuids
+ chmod 755 zsuids
++
++mlmatchup: \
++load mlmatchup.o strerr.a getln.a substdio.a stralloc.a alloc.a error.a \
++str.a fs.a case.a
++ ./load mlmatchup strerr.a getln.a substdio.a stralloc.a \
++ alloc.a error.a str.a fs.a case.a
++
++mlmatchup.0: \
++mlmatchup.8
++ nroff -man mlmatchup.8 > mlmatchup.0
++
++mlmatchup.o: \
++compile mlmatchup.c stralloc.h gen_alloc.h gen_alloc.h gen_allocdefs.h \
++strerr.h getln.h substdio.h subfd.h substdio.h readwrite.h exit.h \
++str.h fmt.h scan.h case.h
++ ./compile mlmatchup.c
++
++clean:
++ rm -f `cat TARGETS`
+diff -x .svn -Naur qmailanalog-0.70/man.do qmailanalog/man.do
+--- qmailanalog-0.70/man.do 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/man.do 2007-04-30 20:57:24.000000000 +0200
+@@ -1,4 +1,4 @@
+ dependon \
+-matchup.0 columnt.0 \
++matchup.0 mlmatchup.0 columnt.0 \
+ xqp.0 xsender.0 xrecipient.0 \
+ alloc.0 case.0 error.0 error_str.0 getln2.0 getln.0 stralloc.0
+diff -x .svn -Naur qmailanalog-0.70/matchup.1 qmailanalog/matchup.1
+--- qmailanalog-0.70/matchup.1 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/matchup.1 2007-04-30 20:57:24.000000000 +0200
+@@ -7,7 +7,9 @@
+ .B matchup
+ reads a series of lines from
+ .BR qmail-send ,
+-with a numeric timestamp in front of each line.
++with a numeric timestamp in the format seconds.nanoseconds or a TAI64N timestamps
++in front of each line, allowing either splogger(8) or multilog(8) to produce the
++logfiles.
+ .B matchup
+ matches the end of each delivery attempt with the start of the delivery attempt
+ and with the relevant message information;
+@@ -108,4 +110,6 @@
+ xsender(1),
+ accustamp(1),
+ qmail-log(5),
+-splogger(8)
++splogger(8),
++multilog(8),
++mlmatchup(1)
+diff -x .svn -Naur qmailanalog-0.70/matchup.c qmailanalog/matchup.c
+--- qmailanalog-0.70/matchup.c 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/matchup.c 2007-04-30 20:57:24.000000000 +0200
+@@ -183,6 +183,47 @@
+ poolbytes = pool.len; /* redundant, but doesn't hurt */
+ }
+
++/* turn TAI date into old fashioned date */
++/* dates without @ are left alone */
++
++static char datebuf[FMT_ULONG+FMT_ULONG+2]; /* ssssssssss.ffffffffff\n */
++
++char *
++datize(s)
++char *s;
++{
++ int c;
++ int len;
++ unsigned long u;
++ unsigned long seconds = 0;
++ unsigned long nanoseconds = 0;
++
++ if(*s != '@') return s;
++ s++;
++
++ while ((c = *s++)) {
++ u = c - '0';
++ if (u >= 10) {
++ u = c - 'a';
++ if (u >= 6) break;
++ u += 10;
++ }
++ seconds <<= 4;
++ seconds += nanoseconds >> 28;
++ nanoseconds &= 0xfffffff;
++ nanoseconds <<= 4;
++ nanoseconds += u;
++ }
++ seconds -= 4611686018427387914ULL;
++
++ len = fmt_ulong(datebuf, seconds);
++ datebuf[len++] = '.';
++ len += fmt_uint0(datebuf+len, nanoseconds, 9);
++ datebuf[len] = 0;
++
++ return datebuf;
++}
++
+ stralloc line = {0};
+ int match;
+
+@@ -209,7 +250,7 @@
+ dmsg.u[dpos] = m;
+
+ dstart.u[dpos] = pool.len;
+- if (!stralloc_cats(&pool,line.s + field[0])) nomem();
++ if (!stralloc_cats(&pool,datize(line.s + field[0]))) nomem();
+ if (!stralloc_0(&pool)) nomem();
+
+ dchan.u[dpos] = pool.len;
+@@ -267,7 +308,7 @@
+ if (mpos != -1) {
+ outs(pool.s + birth.u[mpos]);
+ outs(" "); outs(pool.s + dstart.u[dpos]);
+- outs(" "); outs(line.s + field[0]);
++ outs(" "); outs(datize(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]);
+@@ -279,7 +320,7 @@
+ else {
+ outs(pool.s + dstart.u[dpos]);
+ outs(" "); outs(pool.s + dstart.u[dpos]);
+- outs(" "); outs(line.s + field[0]);
++ outs(" "); outs(datize(line.s + field[0]));
+ outs(" 0 ? "); outs(pool.s + dchan.u[dpos]);
+ outs("."); outs(pool.s + drecip.u[dpos]);
+ outs(" ? ? "); outs(reason);
+@@ -313,7 +354,7 @@
+ if (mpos == -1) return;
+
+ outs("m "); outs(pool.s + birth.u[mpos]);
+- outs(" "); outs(line.s + field[0]);
++ outs(" "); outs(datize(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]));
+@@ -344,7 +385,7 @@
+ numz.u[mpos] = 0;
+
+ birth.u[mpos] = pool.len;
+- if (!stralloc_cats(&pool,line.s + field[0])) nomem();
++ if (!stralloc_cats(&pool,datize(line.s + field[0]))) nomem();
+ if (!stralloc_0(&pool)) nomem();
+
+ sender.u[mpos] = pool.len;
+diff -x .svn -Naur qmailanalog-0.70/mlmatchup.8 qmailanalog/mlmatchup.8
+--- qmailanalog-0.70/mlmatchup.8 1970-01-01 01:00:00.000000000 +0100
++++ qmailanalog/mlmatchup.8 2007-04-30 20:57:24.000000000 +0200
+@@ -0,0 +1,33 @@
++.TH mlmatchup 8
++.SH NAME
++mlmatchup \- collect information on messages and deliveries through multilog
++.SH SYNTAX
++.B mlmatchup
++.SH DESCRIPTION
++.B mlmatchup
++behaves exactly like
++.BR matchup(1)
++with the difference, that it first reads (pending delivery) lines
++from file descriptor 4. This makes
++.B mlmatchup
++suitable as a procesor action for multilog.
++
++If you use multilog to process
++.B qmail-send
++logfiles expand the run file of qmail-send's log services like this:
++
++.EX
++ exec setuidgid qmaill multilog t ./main \\
++.br
++ !/usr/local/qmailanalog/bin/mlmatchup ./qmailanalog
++.EE
++
++.SH "SEE ALSO"
++multilog(8),
++matchup(1),
++xqp(1),
++xrecipient(1),
++xsender(1),
++accustamp(1),
++qmail-log(5),
++splogger(8)
+diff -x .svn -Naur qmailanalog-0.70/mlmatchup.c qmailanalog/mlmatchup.c
+--- qmailanalog-0.70/mlmatchup.c 1970-01-01 01:00:00.000000000 +0100
++++ qmailanalog/mlmatchup.c 2007-04-30 20:57:24.000000000 +0200
+@@ -0,0 +1,536 @@
++#include "stralloc.h"
++#include "gen_alloc.h"
++#include "gen_allocdefs.h"
++#include "strerr.h"
++#include "getln.h"
++#include "substdio.h"
++#include "subfd.h"
++#include "readwrite.h"
++#include "exit.h"
++#include "str.h"
++#include "fmt.h"
++#include "scan.h"
++#include "case.h"
++
++#define FATAL "matchup: fatal: "
++
++void nomem() { strerr_die2x(111,FATAL,"out of memory"); }
++void die_read() { strerr_die2sys(111,FATAL,"unable to read input: "); }
++void die_write() { strerr_die2sys(111,FATAL,"unable to write output: "); }
++void die_write5() { strerr_die2sys(111,FATAL,"unable to write fd 5: "); }
++
++void out(buf,len) char *buf; int len;
++{ if (substdio_put(subfdout,buf,len) == -1) die_write(); }
++void outs(buf) char *buf;
++{ if (substdio_puts(subfdout,buf) == -1) die_write(); }
++
++char buf5[512];
++substdio ss5 = SUBSTDIO_FDBUF(write,5,buf5,sizeof buf5);
++
++void out5(buf,len) char *buf; int len;
++{ if (substdio_put(&ss5,buf,len) == -1) die_write5(); }
++void outs5(buf) char *buf;
++{ if (substdio_puts(&ss5,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(m)
++unsigned long m;
++{
++ int i;
++ for (i = 0;i < nummsg;++i) if (msg.u[i] == m) return i;
++ return -1;
++}
++
++int msg_add(m)
++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;
++}
++
++int msg_kill(i)
++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(d)
++unsigned long d;
++{
++ int i;
++ for (i = 0;i < numdel;++i) if (del.u[i] == d) return i;
++ return -1;
++}
++
++int del_add(d)
++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(i)
++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 */
++}
++
++/* turn TAI date into old fashioned date */
++/* dates without @ are left alone */
++
++static char datebuf[FMT_ULONG+FMT_ULONG+2]; /* ssssssssss.ffffffffff\n */
++
++char *
++datize(s)
++char *s;
++{
++ int c;
++ int len;
++ unsigned long u;
++ unsigned long seconds = 0;
++ unsigned long nanoseconds = 0;
++
++ if(*s != '@') return s;
++ s++;
++
++ while ((c = *s++)) {
++ u = c - '0';
++ if (u >= 10) {
++ u = c - 'a';
++ if (u >= 6) break;
++ u += 10;
++ }
++ seconds <<= 4;
++ seconds += nanoseconds >> 28;
++ nanoseconds &= 0xfffffff;
++ nanoseconds <<= 4;
++ nanoseconds += u;
++ }
++ seconds -= 4611686018427387914ULL;
++
++ len = fmt_ulong(datebuf, seconds);
++ datebuf[len++] = '.';
++ len += fmt_uint0(datebuf+len, nanoseconds, 9);
++ datebuf[len] = 0;
++
++ return datebuf;
++}
++
++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,datize(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(datize(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(datize(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(datize(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,datize(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 (substdio_flush(&ss5) == -1) die_write5();
++}
++
++stralloc outline = {0};
++
++void matchup(substdio *ssin)
++{
++ int i;
++ int j;
++ char ch;
++
++ for (;;) {
++ if (getln(ssin,&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);
++ }
++ }
++}
++
++char subfd4_input[SUBSTDIO_INSIZE];
++static substdio i4t = SUBSTDIO_FDBUF(subfd_read,4,subfd4_input,sizeof subfd4_input);
++substdio *subfd4in = &i4t;
++
++void 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();
++
++ matchup(subfd4in);
++ matchup(subfdin);
++
++ if (substdio_flush(subfdout) == -1) die_write();
++
++ pending();
++
++ _exit(0);
++}
+diff -x .svn -Naur qmailanalog-0.70/prog.do qmailanalog/prog.do
+--- qmailanalog-0.70/prog.do 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/prog.do 2007-04-30 20:57:24.000000000 +0200
+@@ -1,5 +1,6 @@
+ dependon \
+ matchup \
++mlmatchup \
+ columnt \
+ zoverall \
+ zsendmail \
+diff -x .svn -Naur qmailanalog-0.70/TARGETS qmailanalog/TARGETS
+--- qmailanalog-0.70/TARGETS 1998-08-30 23:39:26.000000000 +0200
++++ qmailanalog/TARGETS 2007-05-03 00:14:59.000000000 +0200
+@@ -70,6 +70,9 @@
+ case_lowers.o
+ case.a
+ matchup
++mlmatchup
++mlmatchup.o
++mlmatchup.0
+ columnt.o
+ slurpclose.o
+ columnt
+diff -x .svn -Naur qmailanalog-0.70/zdeferrals.sh qmailanalog/zdeferrals.sh
+--- qmailanalog-0.70/zdeferrals.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zdeferrals.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -5,4 +5,4 @@
+ * xdelay is the total xdelay on those deliveries.
+ '
+ ( echo del xdelay reason
+-HOME/bin/deferrals | sort +2 ) | HOME/bin/columnt | tr _ ' '
++HOME/bin/deferrals | sort -k2 ) | HOME/bin/columnt | tr _ ' '
+diff -x .svn -Naur qmailanalog-0.70/zfailures.sh qmailanalog/zfailures.sh
+--- qmailanalog-0.70/zfailures.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zfailures.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -5,4 +5,4 @@
+ * xdelay is the total xdelay on those deliveries.
+ '
+ ( echo del xdelay reason
+-HOME/bin/failures | sort +2 ) | HOME/bin/columnt | tr _ ' '
++HOME/bin/failures | sort -k2 ) | HOME/bin/columnt | tr _ ' '
+diff -x .svn -Naur qmailanalog-0.70/zrecipients.sh qmailanalog/zrecipients.sh
+--- qmailanalog-0.70/zrecipients.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zrecipients.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -7,4 +7,4 @@
+ * xdelay is the total xdelay incurred by this recipient.
+ '
+ ( echo sbytes mess tries xdelay recipient
+-HOME/bin/recipients | sort +4 ) | HOME/bin/columnt
++HOME/bin/recipients | sort -k4 ) | HOME/bin/columnt
+diff -x .svn -Naur qmailanalog-0.70/zrhosts.sh qmailanalog/zrhosts.sh
+--- qmailanalog-0.70/zrhosts.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zrhosts.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -7,4 +7,4 @@
+ * xdelay is the total xdelay incurred by this host.
+ '
+ ( echo sbytes mess tries xdelay host
+-HOME/bin/rhosts | sort +4 ) | HOME/bin/columnt
++HOME/bin/rhosts | sort -k4 ) | HOME/bin/columnt
+diff -x .svn -Naur qmailanalog-0.70/zsenders.sh qmailanalog/zsenders.sh
+--- qmailanalog-0.70/zsenders.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zsenders.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -10,4 +10,4 @@
+ * xdelay is the total xdelay incurred by this sender.
+ '
+ ( echo mess bytes sbytes rbytes recips tries xdelay sender
+-HOME/bin/senders | sort -n +7 ) | HOME/bin/columnt
++HOME/bin/senders | sort -k7,7n ) | HOME/bin/columnt
+diff -x .svn -Naur qmailanalog-0.70/zsuccesses.sh qmailanalog/zsuccesses.sh
+--- qmailanalog-0.70/zsuccesses.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zsuccesses.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -5,4 +5,4 @@
+ * xdelay is the total xdelay on those deliveries.
+ '
+ ( echo del xdelay reason
+-HOME/bin/successes | sort +2 ) | HOME/bin/columnt | tr _ ' '
++HOME/bin/successes | sort -k2 ) | HOME/bin/columnt | tr _ ' '
+diff -x .svn -Naur qmailanalog-0.70/zsuids.sh qmailanalog/zsuids.sh
+--- qmailanalog-0.70/zsuids.sh 1998-08-30 23:39:27.000000000 +0200
++++ qmailanalog/zsuids.sh 2007-04-30 20:57:24.000000000 +0200
+@@ -10,4 +10,4 @@
+ * xdelay is the total xdelay incurred by this uid.
+ '
+ ( echo mess bytes sbytes rbytes recips tries xdelay uid
+-HOME/bin/suids | sort -n +7 ) | HOME/bin/columnt
++HOME/bin/suids | sort -k7,7n ) | HOME/bin/columnt