&1"; asDbg($cmd, 1); $out = exec($cmd, $output, $rrd_error_val); if ($rrd_error_val) { if (!is_numeric($rrd_error_val)) { $rrd_error_val = $output[0]; } return false; } asDbg($output); if (preg_match("/(\d+)x(\d+)/", $output[0], $matches)) { $retval["xsize"] = $matches[1]; $retval["ysize"] = $matches[2]; } else { $rrd_error_val = $output[0]; return false; } array_shift($output); foreach ($output as $index => $value) { $retval[calcpr][$index] = $value; } return $retval; } function rrd_error() { global $rrd_error_val; return $rrd_error_val; } } /* * Timing function to work out how long things take */ function elapsed($start) { $end = microtime(); list($start2, $start1) = explode(" ", $start); list($end2, $end1) = explode(" ", $end); $diff1 = $end1 - $start1; $diff2 = $end2 - $start2; if( $diff2 < 0 ){ $diff1 -= 1; $diff2 += 1.0; } return $diff2 + $diff1; } if (isset($_SERVER["REQUEST_URI"])) { // web environment $fullpage = true; $outdir = "img"; } else { // Stand-alone command line usage $cmd = true; $outdir = $_SERVER["PWD"]; } if (isset($GLOBALS["rate"])) { $rate = $GLOBALS["rate"]; } else { $rate = 60; } if (isset($fullpage) || isset($cmd)) { asHtmlStart(); if (asLoadStats()) { $minsec = 60; $hoursec = 60 * $minsec; $daysec = 24 * $hoursec; $weeksec = 7 * $daysec; $now = time(); print "

Daily Graphs

\n"; print asPGraph("$outdir/passed-day.png", $now, $daysec, "by day"); print asVGraph("$outdir/virus-day.png", $now, $daysec, "by day"); print "

Weekly Graphs

\n"; print asPGraph("$outdir/passed-week.png", $now, 7*$daysec, "by week"); print asVGraph("$outdir/virus-week.png", $now, 7*$daysec, "by week"); print "

Monthly Graphs

\n"; print asPGraph("$outdir/passed-month.png", $now, 31*$daysec, "by month"); print asVGraph("$outdir/virus-month.png", $now, 31*$daysec, "by month"); print "

Yearly Graphs

\n"; print asPGraph("$outdir/passed-year.png", $now, 365*$daysec, "by year"); print asVGraph("$outdir/virus-year.png", $now, 365*$daysec, "by year"); } else { asMsg("No statistics available."); } asHtmlEnd(); } function asDbg($txt = "", $pre = 0) { if (isset( $GLOBALS["debug"] )) { if ($pre) { print "
\n";
        }
        print "amavis-stats::debug: $txt\n";
        if (is_array($txt)) {
            print "
\n";
            print_r($txt);
            print "
\n"; } if ($pre) { print "
\n"; } print "
\n"; } } function asMsg($txt = "") { print "amavis-stats: $txt
\n"; } function asErr($txt = "") { print "amavis-stats::error: $txt
\n"; } function asHtmlStart() { print '

Amavis Detection Statistics

'; } function asHtmlEnd() { global $asVersion, $rrd; print '
[Generated by amavis-stats version ' . $asVersion . ' using ' . $rrd . ' rrdtool ['; if (!isset($GLOBALS["debug"])) { print 'debug'; } else { print 'nodebug'; } print "].\n"; if (!$GLOBALS["rate"] || ($GLOBALS["rate"] == 60)) { print 'Rate per hour'; } else { print 'Rate per minute'; } print '] '; } /* * */ function asLoadStats () { global $as_libdir, $virus, $pid, $psid, $iid, $bid,$nid,$nsid, $lastupdate, $maxi; $as_libdir = "/var/lib/amavis-stats"; $as_statefile = $as_libdir . "/amavis-stats.state"; $as_namefile = $as_libdir . "/amavis-stats.names"; $as_seenfile = $as_libdir . "/amavis-stats.seen"; $readfile = @file($as_namefile); if (!is_array($readfile)) { asErr("Couldn't open id => name mappings file."); } asDbg("$as_namefile"); asDbg($readfile); $virus = array(); $pid = -1; $iid = -1; $bid = -1; $sid = -1; for ($k = 0; $k <= (count($readfile) - 1); $k++) { $fields = preg_split("/\s+/",$readfile[$k], 2, PREG_SPLIT_NO_EMPTY); $fields[0] = trim($fields[0]); $fields[1] = trim($fields[1]); $virus[$fields[0]]["id"] = $fields[0]; $virus[$fields[0]]["name"] = $fields[1]; if ($fields[1] == "Passed") { $pid = $fields[0]; } elseif ($fields[1] == "Passed(SPAM)") { $psid = $fields[0]; } elseif ($fields[1] == "Infected") { $iid = $fields[0]; } elseif ($fields[1] == "Banned") { $bid = $fields[0]; } elseif ($fields[1] == "Not-Delivered") { $nid = $fields[0]; } elseif ($fields[1] == "Not-Delivered(SPAM)") { $nsid = $fields[0]; } } $readfile = @file($as_seenfile); if (!is_array($readfile)) { asErr("Couldn't open first/last seen file."); } asDbg("$as_seenfile"); asDbg($readfile); for ($k = 0; $k <= (count($readfile) - 1); $k++) { $fields = preg_split("/\s+/",$readfile[$k], -1, PREG_SPLIT_NO_EMPTY); $virus[$fields[0]]["firstseen"] = $fields[1]; $virus[$fields[0]]["lastseen"] = $fields[2]; } $readfile = @file($as_statefile); if (!is_array($readfile)) { asErr("Couldn't open state file."); } asDbg("$as_statefile"); asDbg($readfile); for ($k = 0; $k <= (count($readfile) - 1); $k++) { $fields = preg_split("/\s+/",$readfile[$k], -1, PREG_SPLIT_NO_EMPTY); if ($fields[0] == "lastupdate:" && is_numeric($fields[1])) { $lastupdate = $fields[1]; } elseif ($fields[0] == "LC_TIME:") { setlocale(LC_TIME, $fields[1]); } } if (!isset($lastupdate)) { asErr("lastupdate not defined."); return false; } elseif ($lastupdate == 0) { asErr("last update was at 0 seconds."); return false; } as_col(); return true; } function as_col() { global $as_colors; $as_colors = array( "#00BFFF", /* DeepSkyBlue */ "#FFD700", /* gold */ "#FA8072", /* salmon */ "#006400", /* DarkGreen */ "#FF1493", /* DeepPink */ "#00CED1", /* DarkTurquoise */ "#FF00FF", /* magenta */ "#00FF7F", /* SpringGreen */ "#FF0000", /* red */ "#228B22", /* ForestGreen */ "#F0E68C", /* khaki */ "#FFFF00", /* yellow */ "#0000FF", /* blue */ "#CD5C5C", /* IndianRed */ "#6A5ACD", /* SlateBlue */ "#F4A460", /* SandyBrown */ "#FFA500", /* orange */ "#FF8C00", /* DarkOrange */ "#000080", /* NavyBlue */ "#FF69B4", /* HotPink */ "#2E8B57", /* SeaGreen */ "#A020F0", /* purple */ "#FFB6C1", /* LightPink */ "#0000CD", /* MediumBlue */ "#B22222", /* firebrick */ "#7CFC00", /* LawnGreen */ "#D02090", /* VioletRed */ "#6495ED" /* CornflowerBlue */ ); } /* * */ function addopts(&$opts, $type, $id, $vcount, $virus, $length) { global $as_libdir, $as_colors, $rate, $maxi; $name = sprintf("%-".$maxi."s", $virus[$id]["name"]); $count = $vcount[$id]; $count = sprintf("%8d", $count); // $col = $as_colors[md5($name) % (count($as_colors) - 1)]; $col = substr(md5($name),7,6); // print "COL: $col
\n"; $opts[] = "DEF:v$id=$as_libdir/$id.rrd:hits:AVERAGE"; $opts[] = "CDEF:gv$id=v$id,$rate,*"; // $opts[] = "CDEF:gv$id=v$id,UN,0,v$id,IF,$rate,*"; $opts[] = "$type:gv$id#$col:$name $count"; return $opts; } /* * asVGraph (file, - name of the png to generate * endtime, - end time in seconds (defaults to 'now') * length, - length of time in seconds * timetext,- human-readable description of length (eg: 'by day') * hostname,- hostname of amavis server (defaults to localhost) * ) * * Build a graph of Virus infected emails. * Returns either a html-valid tag which can be printed, or the * boolean "false" if something went wrong. */ function asVGraph($img, $end = 0, $length, $timetext = "", $host = "") { global $as_libdir, $virus, $pid, $psid, $iid, $bid, $nid, $nsid, $lastupdate, $maxi, $rate, $asVersion, $rrdstep; /* * Options... when do we start, end, graph title text etc. */ if ($end == 0) { $end = time(); } // make the end time an even multiple of the rrdstep $end = floor($end/$rrdstep) * $rrdstep; $start = $end - $length; $startdate = strftime("%c", $start); $enddate = strftime("%c", $end); $nowdate = strftime("%c", time()); if ($timetext == "") { $timetext = "$length seconds"; } if ($host == "") { $host = eregi_replace("\n", "", exec('hostname')); } /* * It is a two-step process to build the final graph. The average over * a specific time period seems to be impossible to get without actually * building a graph. Ie, rrd fetch will not calculate the values we * need - we would have to sum and average manually. * * However the PRINT function of a graph will return what we want * in an array. So first of all build a graph that PRINTs the average * of every virus over the selected time period. */ $opts = array(); $opts[] = "--start=$start"; $opts[] = "--end=$end"; foreach ($virus as $id => $rest) { $opts[] = "DEF:v$id=$as_libdir/$id.rrd:hits:AVERAGE"; $opts[] = "CDEF:gv$id=v$id,UN,0,v$id,IF"; $opts[] = "CDEF:gvt$id=gv$id,$length,*"; $opts[] = "PRINT:gvt$id:AVERAGE:%.0lf"; } $ret = rrd_graph($img, $opts, count($opts)); /* * debugging - graph definitions */ asDbg($ret); $infected = 0; if (is_array($ret)) { /* * All results from PRINT commands are in the array $ret[calcpr][..] */ $maxi = 0; $i = 0; foreach ($virus as $id => $rest) { /* * We don't have enough resolution in the rrds * to calculate the correct counts at low averages, * so we just don't display them */ if ($ret['calcpr'][$i] != 0) { $vcount[$id] = $ret['calcpr'][$i]; $maxi = max($maxi, strlen($virus[$id]["name"])); } $i++; /* asDbg("Id: $id = $vcount[$id]"); */ } $maxi++; /* * We usually always have the infected.rrd and passed.rrd 'viruses'. * Take them out of the array (saving the totals) because we don't * really want to graph them. */ if (count($vcount) >= 1) { arsort($vcount); if (isset($vcount[$iid])) { $infected = $vcount[$iid]; unset ($vcount[$iid]); } if (isset($vcount[$pid])) { unset ($vcount[$pid]); } if (isset($vcount[$psid])) { unset ($vcount[$psid]); } if (isset($vcount[$bid])) { unset ($vcount[$bid]); } if (isset($vcount[$nid])) { unset ($vcount[$nid]); } if (isset($vcount[$nsid])) { unset ($vcount[$nsid]); } } else { asDbg("vcount is an empty array"); $vcount = array(); } } else { $msg = rrd_error(); asErr("rrd_graph(): $msg"); return false; } if ($rate == 3600) { $ratemsg = "hour"; } else { $rate = 60; $ratemsg = "min"; } /* * Now that we have the counts of each virus over the time period * we can build the actual graph */ $opts = array(); $opts[] = "--start=$start"; $opts[] = "--end=$end"; $opts[] = "--title=Virus Detection on $host ($timetext)"; $opts[] = "--width=520"; $opts[] = "--vertical-label=viruses/$ratemsg"; // $opts[] = "COMMENT:$infected viruses detected from $startdate\g"; // $opts[] = "COMMENT: to $enddate"; // $opts[] = "COMMENT:\\n"; // $opts[] = "COMMENT:\\n"; /* * The tricky part, building rrd rows but ordering the elements by * columns... */ if ($maxi > 20) { $width = 2; } else { $width = 3; } $total = count($vcount); $depth = ceil($total / $width); $mod = $total % $width; if ($infected > 0) { $keyarray = array_keys ($vcount); for ($d = 1; $d <= $depth; $d++) { for ($col = 1; $col <= $width; $col++) { if ($col == 1) { $index = $d; } elseif ($d != $depth || $mod == 0 || $mod >= $col) { if (($mod == 0) || ($col - $mod) < 2) { $index = ($col - 1) * $depth + $d; } else { $index = $mod * $depth + ($col - $mod - 1)*($depth - 1) + $d ; } } else { continue; } $id = $keyarray[$index - 1]; if ($d == 1 && $col == 1) { addopts($opts, "AREA", $id, $vcount, $virus, $length); } else { addopts($opts, "STACK", $id, $vcount, $virus, $length); } } // $opts[] = "COMMENT:" . str_replace(":", "\:", $enddate) . "\\n"; } } $opts[] = "COMMENT:\\n"; $opts[] = "COMMENT:amavis-stats v$asVersion "; // $opts[] = "COMMENT:$enddate \\r"; asDbg($opts); $ret = rrd_graph("/usr/share/amavis-stats/$img" , $opts, count($opts)); if (!is_array($ret)) { $err = rrd_error(); asErr("rrd_graph(): $err"); return false; } return "\"[image:\n\n"; } /* * asPGraph ( file, - name of the png to generate * endtime, - end time in seconds (defaults to 'now') * length, - length of time in seconds * timetext,- human-readable description of length (eg: 'by day') * hostname,- hostname of amavis server (defaults to localhost) * ) * * Build a graph of clean or "Passed" emails. * Returns either a html-valid tag which can be printed, or the * boolean "false" if something went wrong. */ function asPGraph($img, $end = 0, $length, $timetext = "", $host = "") { global $as_libdir, $virus, $pid, $psid, $iid, $bid, $nid, $nsid, $lastupdate, $maxi, $rate, $asVersion, $rrdstep; /* * Options... when do we start, end, graph title text etc. */ if ($end == 0) { $end = time(); } // make the end time an even multiple of the rrdstep $end = floor($end/$rrdstep) * $rrdstep; $start = $end - $length; $startdate = strftime("%c", $start); $enddate = strftime("%c", $end); $nowdate = strftime("%c", time()); if ($timetext == "") { $timetext = "$length seconds"; } if ($host == "") { $host = eregi_replace("\n", "", exec('hostname')); } if ($rate == 3600) { $ratemsg = "hour"; } else { $rate = 60; $ratemsg = "min"; } $opts = array(); $opts[] = "--start=$start"; $opts[] = "--end=$end"; $opts[] = "--title=Messages Scanned on $host ($timetext)"; $opts[] = "--width=520"; $opts[] = "--vertical-label=msgs/$ratemsg"; $arr = array($pid, $psid, $bid, $iid, $nid, $nsid); $arrcol = array("00ff00", "fA5ACD", "ff0000", "ffff00", "0000ff", "ff3a3d"); $type = "AREA"; foreach ($arr as $idx => $id) { if ($id > 0) { $name = sprintf("%-21s", $virus[$id]["name"]); $col = $arrcol[$idx]; // print "$col
\n"; $opts[] = "DEF:v$id=$as_libdir/$id.rrd:hits:AVERAGE"; $opts[] = "CDEF:gv$id=v$id,UN,0,v$id,IF"; $opts[] = "CDEF:gvt$id=gv$id,$length,*"; $opts[] = "CDEF:gtvt$id=gv$id,$rate,*"; $opts[] = "$type:gtvt$id#$col:$name "; $opts[] = "GPRINT:gvt$id:AVERAGE:%.0lf"; $opts[] = "COMMENT:\\n"; $type = "STACK"; } } /* if ($iid >= 0) { $opts[] = "DEF:v$iid=$as_libdir/$iid.rrd:hits:AVERAGE"; $opts[] = "CDEF:gv$iid=v$iid,UN,0,v$iid,IF"; $opts[] = "CDEF:gvt$iid=gv$iid,$length,*"; $opts[] = "CDEF:gtvt$iid=gv$iid,$rate,*"; $opts[] = "$type:gtvt$iid#FFD700:Infected\: "; $opts[] = "GPRINT:gvt$iid:AVERAGE:%.0lf"; $opts[] = "COMMENT:\\n"; $type = "STACK"; } if ($bid >= 0) { $opts[] = "DEF:v$bid=$as_libdir/$bid.rrd:hits:AVERAGE"; $opts[] = "CDEF:gv$bid=v$bid,UN,0,v$bid,IF"; $opts[] = "CDEF:gvt$bid=gv$bid,$length,*"; $opts[] = "CDEF:gtvt$bid=gv$bid,$rate,*"; $opts[] = "$type:gtvt$bid#FFA500:Banned\: "; $opts[] = "GPRINT:gvt$bid:AVERAGE:%.0lf"; $opts[] = "COMMENT:\\n"; $type = "STACK"; } if ($sid >= 0) { $opts[] = "DEF:v$sid=$as_libdir/$sid.rrd:hits:AVERAGE"; $opts[] = "CDEF:gv$sid=v$sid,UN,0,v$sid,IF"; $opts[] = "CDEF:gvt$sid=gv$sid,$length,*"; $opts[] = "CDEF:gtvt$sid=gv$sid,$rate,*"; $opts[] = "$type:gtvt$sid#FF1493:Spam\: "; $opts[] = "GPRINT:gvt$sid:AVERAGE:%.0lf"; $opts[] = "COMMENT:\\n"; } */ $opts[] = "COMMENT:amavis-stats v$asVersion "; // $opts[] = "COMMENT:$enddate" . str_replace(":", "\:", $enddate) . " \\r"; /* * debugging - graph definitions */ asDbg($opts); $start = microtime(); // $ret = rrd_graph("/usr/share/amavis-stats/$img" , $opts, count($opts)); $ret = rrd_graph("$img" , $opts, count($opts)); $t = elapsed($start); if (!is_array($ret)) { $err = rrd_error(); asErr("rrd_graph(): $err"); return false; } return "\"[image:\n\n"; } ?>