sub build_html_report()

in tools/sa-stats.pl [473:766]


sub build_html_report {
    my $Rh_timing = shift;
    my $Rh_stats = shift;
    my $Rh_userstats = shift;
    my $Rh_aggregate_stats = shift;

    my $rpt = '';

    my $d_now = strftime("%c", localtime(time));
    my $d_start = strftime("%A, %B %e %Y %T %Z", localtime($Rh_timing->{'start'}));
    my $d_end = strftime("%A, %B %e %Y %T %Z", localtime($Rh_timing->{'end'}));
    my $d_telapsed = $Rh_timing->{'telapsed'};
    my $d_period = sprintf("%.2f", $Rh_timing->{'hrsinperiod'});

    my $d_mean_thresh = sprintf("%.2f", $Rh_aggregate_stats->{'threshavg'});

    my $t_spam_overview =<<"T_OVERVIEW";
<table border="1" summary="Aggregate mail statistics">
<tr>
<th rowspan="2"></th>
<th colspan="3">Messages</th>
<th colspan="3">Size</th>
<th colspan="3">Time</th>
<th>Mean Score</th>
</tr>

<tr>
<th>[#]</th>
<th>[#/hr]</th>
<th>[%]</th>
<th>[Kb]</th>
<th>[Kb/hr]</th>
<th>[%]</th>
<th>[s]</th>
<th>[s/hr]</th>
<th>[%]</th>
<th>[#]</th>
</tr>

<tr>
<th bgcolor="#CCFFCC">Ham</th>
<td align="right">$Rh_stats->{'ham'}{'count'}</td>
<td align="right">$Rh_stats->{'ham'}{'perhour'}{'count'}</td>
<td align="right">$Rh_stats->{'ham'}{'percent'}{'count'}</td>
<td align="right">$Rh_stats->{'ham'}{'d_kbytes'}</td>
<td align="right">$Rh_stats->{'ham'}{'perhour'}{'d_kbytes'}</td>
<td align="right">$Rh_stats->{'ham'}{'percent'}{'bytes'}</td>
<td align="right">$Rh_stats->{'ham'}{'d_time'}</td>
<td align="right">$Rh_stats->{'ham'}{'perhour'}{'time'}</td>
<td align="right">$Rh_stats->{'ham'}{'percent'}{'time'}</td>
<td align="right">$Rh_stats->{'ham'}{'d_mean_score'}</td>
</tr>

<tr>
<th bgcolor="#FFCCCC">Spam</th>
<td align="right">$Rh_stats->{'spam'}{'count'}</td>
<td align="right">$Rh_stats->{'spam'}{'perhour'}{'count'}</td>
<td align="right">$Rh_stats->{'spam'}{'percent'}{'count'}</td>
<td align="right">$Rh_stats->{'spam'}{'d_kbytes'}</td>
<td align="right">$Rh_stats->{'spam'}{'perhour'}{'d_kbytes'}</td>
<td align="right">$Rh_stats->{'spam'}{'percent'}{'bytes'}</td>
<td align="right">$Rh_stats->{'spam'}{'d_time'}</td>
<td align="right">$Rh_stats->{'spam'}{'perhour'}{'time'}</td>
<td align="right">$Rh_stats->{'spam'}{'percent'}{'time'}</td>
<td align="right">$Rh_stats->{'spam'}{'d_mean_score'}</td>
</tr>

<tr>
<th bgcolor="#CCCCFF">Total</th>
<td align="right">$Rh_stats->{'total'}{'count'}</td>
<td align="right">$Rh_stats->{'total'}{'perhour'}{'count'}</td>
<td align="right">$Rh_stats->{'total'}{'percent'}{'count'}</td>
<td align="right">$Rh_stats->{'total'}{'d_kbytes'}</td>
<td align="right">$Rh_stats->{'total'}{'perhour'}{'d_kbytes'}</td>
<td align="right">$Rh_stats->{'total'}{'percent'}{'bytes'}</td>
<td align="right">$Rh_stats->{'total'}{'d_time'}</td>
<td align="right">$Rh_stats->{'total'}{'perhour'}{'time'}</td>
<td align="right">$Rh_stats->{'total'}{'percent'}{'time'}</td>
<td align="right">$Rh_stats->{'total'}{'d_mean_score'}</td>
</tr>
</table>
T_OVERVIEW

    my $t_hourly =<<"T_HOURLY";
<table border="0" summary="Hourly ham/spam trends">
<tr>
<th colspan="3">Statistics by hour</th>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>

<tr>
<th>Hour</th>
<th bgcolor="#FFCCCC">Spam</th>
<th bgcolor="#CCFFCC">Ham</th>
<td colspan="10"></td>
</tr>
T_HOURLY

    my $hour = floor($Rh_timing->{'start'}/3600);
    my $prev_day = '';

    my $null_color = 'bgcolor="#CCCCFF"';
    my $spam_color = 'bgcolor="#FFCCCC"';
    my $ham_color = 'bgcolor="#CCFFCC"';
#    my $spam_mark = qq{<td $spamcolor">&nbsp;</td>};
#    my $ham_mark = qq{<td $hamcolor">&nbsp;</td>};
    while ($hour < $Rh_timing->{'end'}/3600) {
        foreach my $partition (qw(spam ham total)) {
            $Rh_stats->{$partition}{'byhour'}{$hour} = 0 unless
                (defined($Rh_stats->{$partition}{'byhour'}{$hour}) &&
                 ($Rh_stats->{$partition}{'byhour'}{$hour} > 0));
        }

        my $curr_hour = strftime("%H:00", localtime($hour*3600));
        my $curr_day = strftime("%Y-%m-%d", localtime($hour*3600));
        if ($curr_day ne $prev_day) {
            $curr_hour = "<b>$curr_day $curr_hour</b>";
        }
        $prev_day = $curr_day;

        my $ham_fraction = 0;
        my $spam_fraction = 0;
        my $check_total = $Rh_stats->{'ham'}{'byhour'}{$hour} + $Rh_stats->{'spam'}{'byhour'}{$hour};
        my $tab_graph = qq{<td colspan="10" $null_color>&nbsp;</td>};
        if ($Rh_stats->{'total'}{'byhour'}{$hour} > 0) {
            $spam_fraction = int(10 * ($Rh_stats->{'spam'}{'byhour'}{$hour} / $check_total));
            $ham_fraction = 10 - $spam_fraction;
            if ($spam_fraction == 10) {
                $tab_graph = qq{<td colspan="10" $spam_color>&nbsp;</td>};
            } elsif ($spam_fraction == 9) {
                $tab_graph = qq{<td colspan="9" $spam_color>&nbsp;</td>};
                $tab_graph .= "<td $ham_color>&nbsp;</td>";
            } elsif ($spam_fraction == 1) {
                $tab_graph = "<td $spam_color>&nbsp;</td>";
                $tab_graph .= qq{<td colspan="9" $ham_color>&nbsp;</td>};
            } elsif ($spam_fraction == 0) {
                $tab_graph = qq{<td colspan="10" $ham_color>&nbsp;</td>};
            } else {
                $tab_graph = qq{<td colspan="$spam_fraction" $spam_color>&nbsp;</td>};
                $tab_graph .= qq{<td colspan="$ham_fraction" $ham_color>&nbsp;</td>};
            }
#            $tab_graph = ($spam_mark x $spam_fraction) . ($ham_mark x $ham_fraction);
        }

        $t_hourly .= sprintf(qq{<tr align="right"><td>%s</td><td>%d</td><td>%d</td>%s</tr>\n},
            $curr_hour,
            $Rh_stats->{'spam'}{'byhour'}{$hour},
            $Rh_stats->{'ham'}{'byhour'}{$hour},
            $tab_graph,);

        $hour++;
    }
    $t_hourly .= "</table>\n";

    my $t_userstats = '';
    if ($opt{'userstats'} && defined($Rh_stats->{'total'}{'count'}) &&
        ($Rh_stats->{'total'}{'count'} > 0)) {
        my $topusers = 25;
        if (defined($opt{'topusers'}) && ($opt{'topusers'} > 0)) {
            $topusers = $opt{'topusers'};
        }

        my $usercount = scalar(keys(%{$Rh_userstats}));
        if ($usercount > 0) {
            my $upper_userlimit = ($usercount > $topusers) ? $topusers : $usercount;

            $t_userstats =<<"T_USERSTATS";
<table border="1" summary="Top $upper_userlimit spam victims">
<tr>
<th colspan="3">Top $upper_userlimit spam victims</th>
<th colspan="6" bgcolor="#FFCCCC">Spam</th>
</tr>
<tr>
<th rowspan="2">User</th>
<th colspan="2">Avg. Score</th>
<th colspan="2">Messages Received</th>
<th colspan="2">Bytes Received</th>
<th colspan="2">Processing Time</th>
</tr>
<tr>
<th bgcolor="#FFCCCC">Spam</th>
<th bgcolor="#CCFFCC">Ham</th>
<th>[#]</th>
<th>%</th>
<th>[bytes]</th>
<th>%</th>
<th>[s]</th>
<th>%</th>
</tr>
T_USERSTATS

#            $rpt .=    "Top $upper_userlimit spam victims:\n";
#            $rpt .=    "User                               S AvScr   H AvScr      Count    % Count      Bytes    % Bytes       Time     % Time\n";
#            $rpt .=    "--------------------------------   -------   -------   -------- ----------   -------- ----------   -------- ----------\n";
        foreach my $user (sort {
          $Rh_userstats->{$b}{'total'}{'count'} <=> $Rh_userstats->{$a}{'total'}{'count'}
          } keys %{$Rh_userstats}) {

            foreach my $partition (qw(spam ham total)) {
                foreach my $metric (qw(score bytes count)) {
                    $Rh_userstats->{$user}{$partition}{$metric} ||= 0;
                }
            }

            my %avg_score = ();
            foreach my $partition (qw(ham spam total)) {

                foreach my $metric (qw(count bytes time)) {
                    $Rh_userstats->{$user}{$partition}{$metric} = 0 unless
                    (defined($Rh_userstats->{$user}{$partition}{$metric}));
                }

                if ($partition ne 'total') {
                    if (defined($Rh_userstats->{$user}{$partition}{'count'})
                      && ($Rh_userstats->{$user}{$partition}{'count'} > 0)) {
                        $avg_score{$partition} = sprintf('%.2f',
                            $Rh_userstats->{$user}{$partition}{'score'}
                            / $Rh_userstats->{$user}{$partition}{'count'});
                    } else {
                        $avg_score{$partition} = 0;
                    }
                }
            }

            $t_userstats .= sprintf(qq{<tr align="right"><td align="left">%s</td><td>%.2f</td><td>%.2f</td><td>%d</td><td>%.2f%%</td><td>%d</td><td>%.2f%%</td><td>%d</td><td>%.2f%%</td></tr>\n},
        $user,
        $avg_score{'spam'},
        $avg_score{'ham'},
        $Rh_userstats->{$user}{'spam'}{'count'},
        (defined($Rh_userstats->{$user}{'total'}{'count'}) && ($Rh_userstats->{$user}{'total'}{'count'} > 0)) ?
        100 * $Rh_userstats->{$user}{'spam'}{'count'} / $Rh_userstats->{$user}{'total'}{'count'} : 0,
        $Rh_userstats->{$user}{'spam'}{'bytes'},
        (defined($Rh_userstats->{$user}{'total'}{'bytes'}) && ($Rh_userstats->{$user}{'total'}{'bytes'} > 0)) ?
         100 * $Rh_userstats->{$user}{'spam'}{'bytes'} / $Rh_userstats->{$user}{'total'}{'bytes'} : 0,
        $Rh_userstats->{$user}{'spam'}{'time'},
        (defined($Rh_userstats->{$user}{'total'}{'time'}) && ($Rh_userstats->{$user}{'total'}{'time'} > 0)) ?
        100 * $Rh_userstats->{$user}{'spam'}{'time'} / $Rh_userstats->{$user}{'total'}{'time'}: 0,
                );
            }

            $t_userstats .= "</table>\n<hr>\n";

        }
    }

    my $codename = $0;
    $codename =~ s#^.*/##o;

    $rpt .=<<"HTMLPAGE";
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>SpamAssassin Statistics: $d_start - $d_end</title>
</head>
<body>
<h1>SpamAssassin Statistics:</h1>
<p>
Period of <b>$d_period</b> hour(s) extending from<br>
<b>$d_start</b> to<br>
<b>$d_end</b>
</p>
<p>
Generated on <b>$d_now</b> in $d_telapsed second(s) by $codename, version $VER_NUM.
</p>
<hr>
<p>
Note: 'ham' = 'nonspam'
</p>
<p>
The mean spam threshold score is $d_mean_thresh; mail scoring below the threshold is ham, mail scoring at or above the threshold is spam.
</p>
$t_spam_overview
<hr>
$t_hourly
<hr>
$t_userstats
<p>
Generated on <b>$d_now</b> in $d_telapsed second(s) by $codename, version $VER_NUM.
</p>
</body>
</html>
HTMLPAGE

    return $rpt;
}