#!/usr/bin/gawk -f # function skipws(s) { sub(/^[ \t\r\n]+/, "", s); return (s); } function eatwords(n, s, i) { for (i=1; i<=n; i++) { q = q " " $i; $i = ""; } $0 = skipws($0); return (skipws(q)); } # If you have gawk-3.1.x with strtonum() then use # this function. function _hex2dec(s) { return (strtonum("0x" s)); } function hex2dec(s, c, i, n, v) { s = toupper(s); n = length(s); for (i=1; i<=n; i++) { c = substr(s, i, 1); v = v * 16 + DEC[c]; } return (v); } function syslog(s) { if (mode == "syslog") printf ("%s\n", s) | syslogcmd; else printf ("%s %s\n", date, s); return (0); } BEGIN { program = "qmail-relog"; STDERR = "/dev/stderr"; mode = "print"; syslogcmd = "logger -i -t qlog"; n = split("0 1 2 3 4 5 6 7 8 9 A B C D E F", x, " "); for (i=1; i<=n; i++) DEC[x[i]] = i - 1; } /./ { if ($1 ~ /^@/) { # multilog `current' tai64n format. p = hex2dec(substr($1, 10, 8)); date = strftime("%Y-%m-%d %H:%M:%S", p); sub(/^[^ \t]+[ \t]+/, "", $0); # eatwords(1); } else if ($0 ~ /[A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:/ && $6 ~ /^[0-9]+\.[0-9]+$/) { # looks like splogger/syslog. date = strftime("%Y-%m-%d %H:%M:%S", $6); sub(/^.*: [0-9]+\.[0-9]+[ \t]+/, "", $0); # eatwords(6); } else { # assuming "multilog archived log" format. date = $1 " " $2; sub(/\..*/, "", date); sub(/^[^ \t]+[ \t]+[^ \t]+[ \t+]/, "", $0); # eatwords(2); } if (match($0, /status: local/) > 0) next; if (match($0, /new msg ([0-9]+)$/, x) > 0) { id = x[1]; if (id in msg) printf ("%s: duplicate msg number: %d\n", program, id); msg[id] = 1; delete sender[id]; delete size[id]; started[id] = systime(); delivery[id] = 0; } else if (match($0, /info msg ([0-9]+): bytes ([0-9]+) from ([^ \t]+) /, x) > 0) { id = x[1]; size[id] = x[2]; sender[id] = x[3]; } else if (match($0, /starting delivery ([0-9]+): msg ([0-9]+) to (local|remote) ([^ \t]+)/, x) > 0) { dnum = x[1]; id = x[2]; # adr = x[4]; dmsg[dnum] = x[2]; type[dnum] = x[3]; if (x[3] == "remote") dadr[dnum] = "<" x[4] ">"; else if (x[3] == "local") { split(x[4], z, "@"); k = length(z[2]); if (substr(x[4], 1, k + 1) == (z[2] "-")) dadr[dnum] = "<" substr(x[4], k+2) ">"; else dadr[dnum] = "<" x[4] ">"; } else { printf ("%s: script error: %s\n", program, $0) >>STDERR; exit (1); } } else if (match($0, /delivery ([0-9]+): ([a-z]+): (.*)/, x) > 0) { dnum = x[1]; st = x[2]; gsub(/_/, " ", x[3]); gsub(/\/$/, "", x[3]); status = ""; if (! (dnum in dmsg)) { lm = sprintf ("-INFO: unseen delivery number: %d", dnum); syslog(lm); } else { id = dmsg[dnum]; if (st == "success") { if (match(x[3], /(.*)\/([^\/]+)/, y) > 0) status = y[2]; if (type[dnum] == "remote") { rhost = y[1]; sub(/ .*$/, "", rhost); sub(/Remote host said: /, "", status); lm = sprintf ("+OK: sender= %s, rcpt= %s, size= %d, server= %s, delay= %d, m= %d-%d, d= %d, status= %s", sender[id], dadr[dnum], size[id], rhost, systime() - started[id], started[id], id, dnum, status); } else { rhost = "local"; status = "delivered"; lm = sprintf ("** +OK: sender= %s, rcpt= %s, size= %d, server= %s, delay= %d, m= %d-%d, d= %d, status= %s", sender[id], dadr[dnum], size[id], rhost, systime() - started[id], started[id], id, dnum, status); } syslog(lm); } else { status = rhost = "unknown"; if (match(x[3], /([^\/]+)\/(.*)\/([^\/]+)/, y) > 0) status = y[2]; if (match(y[1], /^([1-9][0-9]?[0-9]?\.[^ ]+)/, x) > 0) rhost = x[1]; if (status ~ /^Remote host said: /) { status = substr(status, 19); } else { p = y[1]; if (p ~ /able to establish/) status = "connection error"; else status = y[1]; sub(/^Sorry,/, "qmail:", status); } lm = sprintf ("%s: sender= %s, rcpt= %s, size= %d, server= %s, m= %d, d= %d, error= %s", (st == "deferral")? "-INFO": "-ERR", sender[id], dadr[dnum], size[id], rhost, id, dnum, status); syslog(lm); } delete dmsg[dnum]; delete dadr[dnum]; } } else if (match($0, /bounce msg ([0-9]+) /, x) > 0) { } else if (match($0, /end msg ([0-9]+)$/, x) > 0) { if (! (id in msg)) { lm = sprintf ("-INFO: unseen msg number: %d", id); syslog(lm); } else { delete msg[id]; delete started[id]; delete delivery[id]; delete size[id]; delete sender[id]; } } else { printf ("%s: unmatched line: %s\n", program, $0) >>STDERR; } } END { for (id in msg) { printf ("open message delivery: %d\n", id); } }