#! /bin/bash # $Id: xferfaxstats.sh.in 851 2008-06-18 05:12:47Z faxguy $ # # HylaFAX Facsimile Software # # Copyright (c) 1990-1996 Sam Leffler # Copyright (c) 1991-1996 Silicon Graphics, Inc. # HylaFAX is a trademark of Silicon Graphics # # Permission to use, copy, modify, distribute, and sell this software and # its documentation for any purpose is hereby granted without fee, provided # that (i) the above copyright notices and this permission notice appear in # all copies of the software and related documentation, and (ii) the names of # Sam Leffler and Silicon Graphics may not be used in any advertising or # publicity relating to the software without the specific, prior written # permission of Sam Leffler and Silicon Graphics. # # THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, # EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY # WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. # # IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR # ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, # OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, # WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF # LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE # OF THIS SOFTWARE. # # # Print Statistics about Transmitted Facsimile. # SPOOL=/var/spool/hylafax . $SPOOL/bin/common-functions test -f $SPOOL/etc/setup.cache || { cat< 0) { t -= v*3600; result = v ":" } v = int(t/60); if (v >= 10 || result != "") result = result digits[int(v/10)]; result = result digits[int(v%10)]; t -= v*60; return (result ":" digits[int(t/10)] digits[int(t%10)]); } # # Setup map for histogram calculations # and indexed table for decoding params. # function setupMaps(s, map, names) { n = split(s, a, ":"); for (i = 1; i <= n; i++) { map[a[i]] = i; names[i-1] = a[i]; } } # # Add pages to a histogram. # function addToMap(key, ix, pages, map) { if (key == "") { for (i in map) key = key ":"; } n = split(key, a, ":"); a[map[ix]] += pages; t = a[1]; for (i = 2; i <= n; i++) t = t ":" a[i]; return t; } # # Merge two histogram maps. # function mergeMap(map2, map1) { if (map2 == "") return map1; else if (map1 == "") return map2; # map1 & map2 are populated n1 = split(map1, a1, ":"); n2 = split(map2, a2, ":"); for (i = 1; i <= n1; i++) a2[i] += a1[i]; t = a2[1]; for (i = 2; i <= n; i++) t = t ":" a2[i]; return t; } # # Return the name of the item with the # largest number of accumulated pages. # function bestInMap(totals, map) { n = split(totals, a, ":"); imax = 1; max = -1; for (j = 1; j <= n; j++) if (a[j] > max) { max = a[j]; imax = j; } split(map, a, ":"); return a[imax]; } # # Sort array a[l..r] # function qsort(a, l, r) { i = l; k = r+1; item = a[l]; for (;;) { while (i < r) { i++; if (a[i] >= item) break; } while (k > l) { k--; if (a[k] <= item) break; } if (i >= k) break; t = a[i]; a[i] = a[k]; a[k] = t; } t = a[l]; a[l] = a[k]; a[k] = t; if (k != 0 && l < k-1) qsort(a, l, k-1); if (k+1 < r) qsort(a, k+1, r); } function cleanup(s) # remove special characters from the string s and return the results # the first arg of gsub is a regex to be substituted (removed in this # case) from the string s # remove double quotes, leading spaces at the beginning # of the string any spaces followed at the end of the string { gsub("\"", "", s); gsub("^ +", "", s); gsub(" +$", "", s); return s; } function setupToLower() { upperRE = "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]"; upper["A"] = "a"; upper["B"] = "b"; upper["C"] = "c"; upper["D"] = "d"; upper["E"] = "e"; upper["F"] = "f"; upper["G"] = "g"; upper["H"] = "h"; upper["I"] = "i"; upper["J"] = "j"; upper["K"] = "k"; upper["L"] = "l"; upper["M"] = "m"; upper["N"] = "n"; upper["O"] = "o"; upper["P"] = "p"; upper["Q"] = "q"; upper["R"] = "r"; upper["S"] = "s"; upper["T"] = "t"; upper["U"] = "u"; upper["V"] = "v"; upper["W"] = "w"; upper["X"] = "x"; upper["Y"] = "y"; upper["Z"] = "z"; } function toLower(s) { if (match(s, upperRE) != 0) { do { c = substr(s, RSTART, 1); gsub(c, upper[c], s); } while (match(s, upperRE)); } return s; } function getBR(params) { if ((int(int(params) / 2097152) % 2) == 1) { return brNames[int(int(params) / 8) % 16]; } else { return brNames[int(int(params) / 2) % 8]; } } function getDF(params) { if ((int(int(params) / 2097152) % 2) == 1) { return dfNames[int(int(params) / 16384) % 4]; } else { return dfNames[int(int(params) / 512) % 4]; } } function hex(n) { # GNU Awk 3.1.3 has a type conversion error from hex strings, # so we have to do it the hard way val = 0; for (position = 1; position <= length(n); position++) { val = val * 16; char = tolower(substr(n, position, 1)); if (char == "a") val = val + 10; else if (char == "b") val = val + 11; else if (char == "c") val = val + 12; else if (char == "d") val = val + 13; else if (char == "e") val = val + 14; else if (char == "f") val = val + 15; else val = val + int(char); } return val; } function isBitSet(bit, dcs) { byte = int((bit - 1) / 8); pos = 7 - ((bit - 1) % 8); dcsbyte = hex(substr(dcs, (byte*3+1), 2)); return int(int(dcsbyte / (2 ^ pos)) % 2); } function getDFfromDCS(dcs) { if (substr(dcs, 1, 1) == "\"") dcs = substr(dcs, 2); if (substr(dcs, length(dcs), 1) == "\"") dcs = substr(dcs, 1, length(dcs)-1); if (isBitSet(68, dcs)) { if (isBitSet(69, dcs)) return dfNames[6]; return dfNames[5]; } if (isBitSet(78, dcs) || isBitSet(79, dcs)) return dfNames[4]; if (isBitSet(31, dcs)) return dfNames[3]; if (isBitSet(26, dcs)) return dfNames[2]; if (isBitSet(16, dcs)) return dfNames[1]; return dfNames[0]; } # # Accumulate a statistics record. # function acct(key, dest, pages, time, br, df, status) { status = cleanup(status); if (length(status) > 11) { msg = toLower(substr(status, 1, 11)); if (callFailed[msg]) return; } if (cvtDateTime($1) < KEEPSINCE || cvtDateTime($1) > KEEPEND) return; key = cleanup(key); EOF test "$MAPNAMES" = "yes" && $CAT<<'EOF' # # Try to merge unqualified names w/ fully qualified names # by stripping the host part of the domain address and # mapping unqualified names to a stripped qualified name. # n = split(key, parts, "@"); if (n == 2) { # user@addr user = parts[1]; if (user != "root" && user != "guest") { addr = parts[2]; # # Strip hostname from multi-part domain name. # EOF test "$MAPNAMES" = "yes" && echo 'p = split("'`hostname`'", hostname, ".");' test "$MAPNAMES" = "yes" && $CAT<<'EOF' n = split(addr, domains, "."); if (p > 1 && n > p) { # e.g. flake.asd.sgi.com l = length(domains[1])+1; addr = substr(addr, l+1, length(addr)-l); key = user "@" addr; } if (addrs[user] == "") { # record mapped name addrs[user] = addr; } else if (addrs[user] != addr) { if (!warned[user "@" addr]) { warned[user "@" addr] = 1; printf "Warning, address clash, \"%s\" and \"%s\".\n", \ user "@" addrs[user], user "@" addr } } } } else if (n != 1) { printf "Warning, weird user address/name \"%s\".\n", key } EOF $CAT<<'EOF' dest = cleanup(dest); sendpages[key] += pages; sendcalls[key] += 1; time = cleanup(time); if (pages == 0 && time > 60) time = 0; sendtime[key] += cvtTime(time); if (status != "") senderrs[key]++; br = cleanup(br); sendrate[key] = addToMap(sendrate[key], br, pages, rateMap); df = cleanup(df); senddata[key] = addToMap(senddata[key], df, pages, dataMap); } # # Print a rule between the stats and the totals line. # function printRule(n, s) { r = ""; while (n-- >= 0) r = r s; printf "%s\n", r; } BEGIN { FS="\t"; rates = "2400:4800:7200:9600:12000:14400:16800:19200:21600:24000:26400:28800:31200:33600"; setupMaps(rates, rateMap, brNames); datas = "1-D MH:2-D MR:2-D Uncompressed Mode:2-D MMR:JBIG:JPEG Greyscale:JPEG Full-color"; setupMaps(datas, dataMap, dfNames); callFailed["busy signal"] = 1; callFailed["unknown pro"] = 1; callFailed["no carrier "] = 1; callFailed["no local di"] = 1; callFailed["no answer f"] = 1; callFailed["ringback de"] = 1; callFailed["job aborted"] = 1; setupToLower(); setupDateTimeStuff(); if (SINCEDT == "") KEEPSINCE = cvtDateTime(TODAY) - AGE*FULLDAY; else KEEPSINCE = cvtDateTime(SINCEDT); if (ENDDT == "") KEEPEND = cvtDateTime(TODAY); else KEEPEND = cvtDateTime(ENDDT); EOF echo "KeyTitle = \"$KEYTITLE\"" $CAT<<'EOF' } END { OFS="\t"; setupDigits(); maxlen = 15; # merge unqualified and qualified names for (key in sendpages) { if (addrs[key] != "") { fullkey = key "@" addrs[key]; sendpages[fullkey] += sendpages[key]; sendcalls[fullkey] += sendcalls[key]; sendtime[fullkey] += sendtime[key]; senderrs[fullkey] += senderrs[key]; sendrate[fullkey] = \ mergeMap(sendrate[fullkey], sendrate[key]); senddata[fullkey] = \ mergeMap(senddata[fullkey], senddata[key]); } } nsorted = 0; for (key in sendpages) { if (addrs[key] != "") # unqualified name continue; l = length(key); if (l > maxlen) maxlen = l; sorted[nsorted++] = key; } qsort(sorted, 0, nsorted-1); fmt = "%-" maxlen "." maxlen "s"; # e.g. %-24.24s printf fmt " %6s %6s %9s %6s %5s %7s %7s\n", KeyTitle, "Pages", "Calls", "Time", "Pg/min", "Errs", "TypRate", "TypData"; tpages = 0; ttime = 0; terrs = 0; for (k = 0; k < nsorted; k++) { i = sorted[k]; t = sendtime[i]/60; if (t == 0) t = 1; n = sendpages[i]; if (n == 0) n = 1; brate = best printf fmt " %6d %6d %9s %6.1f %5d %7d %7.7s\n", i, sendpages[i], sendcalls[i], fmtTime(sendtime[i]), sendpages[i] / t, senderrs[i], bestInMap(sendrate[i], rates), bestInMap(senddata[i], datas); tpages += sendpages[i]; tcalls += sendcalls[i]; ttime += sendtime[i]; terrs += senderrs[i]; } printRule(maxlen+1+6+1+6+1+9+6+1+5+1+7+1+7, "-"); t = ttime/60; if (t == 0) t = 1; printf fmt " %6d %6d %9s %6.1f %5d\n", "Total", tpages, tcalls, fmtTime(ttime), tpages/t, terrs; } EOF echo "$AWKRULES" )>$tmpAwk $AWK -f $tmpAwk -v TODAY="$TODAY" -v AGE="$AGE" -v SINCEDT="$SINCEDT" -v ENDDT="$ENDDT" $FILES # cleanup hfExit 0