#!/usr/local/bin/perl
#
# wu-ftpd-log analyzer
#
# port of original bash/awk script
#
# Functions :
#
# - Create mail to ftpadmin with yesterdays statistics, including :
#   * anonymous uploads (complete logentries)
#   * total anonymous downloads (bytes, files)
#   * total realuser uploads (bytes, files)
#   * total realuser downloads (bytes, files)
#
# - Create html document with statistics, including :
#   * total anonymous uploads yesterday (bytes, files)
#   * total anonymous downloads yesterday (bytes, files)
#   * top-most-downloaded files
#

# WUFTPLOG = Name of logfile to open

$WUFTPLOG = "/var/adm/ftpd/xferlog";

# FTPADMIN = where to report to. "|mail -s \"FTP server usage report\" ftpadmin" to mail or ">ftpreport" to save to file

$FTPADMIN = "|mail -s \"FTP server usage report\" ftpadmin";

# HTMLOUT = Name of html file to create (with the >)

$HTMLOUT = ">/home/www/htdocs/system/ftpusage.html";

# HTTITLE = Title for html page

$HTTITLE ="Ftp Usage for ftp.cetis.hvu.nl";

# FTPURLPRE = prepended URL for most ftped files list

$FTPURLPRE ="ftp://ftp.cetis.hvu.nl";

# That's it for configuration

# Initialize counters

$yesterdayanondlfiles = 0;
$yesterdayanondlbytes = 0;
$yesterdayanonulfiles = 0;
$yesterdayanonulbytes = 0;
$yesterdayuserdlbytes = 0;
$yesterdayuserdlfiles = 0;
$yesterdayuserulbytes = 0;
$yesterdayuserulfiles = 0;

$totalanondlfiles = 0;
$totalanondlbytes = 0;

# Find yesterday's date

$yesmday=(localtime(time - 86400))[3];
$yesmonth=(Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[(localtime(time - 86400))[4]];
$yesyear=1900+(localtime(time - 86400))[5];

# open files

open (LOGFILE,$WUFTPLOG) || die "Can't open $WUFTPLOG.\n";

open (HTMLFILE,$HTMLOUT) || die "Can't open $HTMLFILE for output.\n";

open (REPORT,$FTPADMIN) || die "Can't open $REPORT for output.\n";

# write header report

printf REPORT "\nFTP server usage report for $yesmday $yesmonth $yesyear\n";
printf REPORT "\nIncoming anonymous files :\n";
printf REPORT "-------------------------------------------------------------\n";

# start reading

while (<LOGFILE>) {

	# Split the line into fields

	# split on both single and double spaces

	($weekday,$month,$monthday,$time,$year,$duration,$host,$filesize,$filename,$transmode,$underscore,$direction,$usermode,$name,$protocol,$identopts,$identname)
		= split(/ +/o,$_);

	# work on fields

	# check for the total anonymous d/l

	if ( $usermode eq "a" && $direction eq "o" ) {
		$totalanondlfiles ++;
		$totalanondlbytes += $filesize;
		$filecount{$filename}++;
	}

	# check for yesterday

	if ( $yesyear == $year && $yesmonth eq $month && $yesmday == $monthday ) {

		# check type

		# realuser, incoming

		if ( $usermode eq "r" && $direction eq "i" ) {
			$yesterdayuserulfiles ++;
			$yesterdayuserulbytes += $filesize;
		}

		# realuser, outgoing

		elsif ( $usermode eq "r" && $direction eq "o" ) {
			$yesterdayuserdlfiles ++;
			$yesterdayuserdlbytes += $filesize;
		}

		# anonymous, incoming

		elsif ( $usermode eq "a" && $direction eq "i" ) {
			$yesterdayanonulfiles ++;
			$yesterdayanonulbytes += $filesize;
			printf REPORT "$time $host $filesize $filename $name\n";
		}

		# anonymous, outgoing

		elsif ( $usermode eq "a" && $direction eq "o" ) {
			$yesterdayanondlfiles ++;
			$yesterdayanondlbytes += $filesize;
		}
	}
}

# Make the html report..

printf HTMLFILE "<HTML>\n<HEAD>\n<TITLE>$HTTITLE</TITLE>\n</HEAD>\n<BODY>\n";
printf HTMLFILE "<H1>$HTTITLE for $yesmday $yesmonth $yesyear</H1>\n<HR>\n";
printf HTMLFILE "<H3>Yesterday's anonymous downloads :</H3>\n";
printf HTMLFILE "<PRE>Files : %u\n" , $yesterdayanondlfiles;
printf HTMLFILE "Bytes : %u</PRE>\n<HR>\n", $yesterdayanondlbytes;
printf HTMLFILE "<H3>Yesterday's anonymous uploads :</H3>\n";
printf HTMLFILE "<PRE>Files : %u\n" , $yesterdayanonulbytes;
printf HTMLFILE "Bytes : %u</PRE>\n<HR>\n", $yesterdayanonulbytes;
printf HTMLFILE "<H3>Yesterday's realuser downloads :</H3>\n";
printf HTMLFILE "<PRE>Files : %u\n" , $yesterdayuserdlfiles;
printf HTMLFILE "Bytes : %u</PRE>\n<HR>\n", $yesterdayuserdlbytes;
printf HTMLFILE "<H3>Yesterday's realuser uploads :</H3>\n";
printf HTMLFILE "<PRE>Files : %u\n" , $yesterdayuserulfiles;
printf HTMLFILE "Bytes : %u</PRE>\n<HR>\n", $yesterdayuserulbytes;
printf HTMLFILE "<H3>Total anonymous downloads :</H3>\n";
printf HTMLFILE "<PRE>Files : %u\n", $totalanondlfiles;
printf HTMLFILE "Bytes : %u</PRE>\n<HR>\n", $totalanondlbytes;
printf HTMLFILE "<H3>Most anon-ftped files:</H3>\n";
printf HTMLFILE "<PRE>\n";

# The tricky stuff : make two arrays of the names and number of times
# ftped of the anon-ftped files, sorted by descending number of times
# downloaded.
# This got me wondering for a time, until I dug around the 'Programming Perl'
# book (Nutshell).
# The solution : Sorting one array while looking in another array for the keys
# to sort on. (chapter 5 : 'Sorting an array by a computable field')
#
# Better good copied work then badly self-written.

@names=keys(%filecount);
local(@datanum,@sortarr);
foreach $file (keys(%filecount)){
	push(@datanum,$filecount{$file});
}

sub bydatanum { $datanum[$a] <=> $datanum[$b]; }

# here I do an extra trick : because I need the array twice (once for the names
# and once for the downloadcounters) I keep the sorting array in a temp array,
# to avoid doing a sort run twice.

@sortarr=reverse sort bydatanum $[..$#names;
@sortdata=@names[@sortarr];
@sortnum=@datanum[@sortarr];
undef %filecount;
undef @sortarr;

foreach $cnt ($[..$#sortdata){
	printf HTMLFILE "%5d <A HREF=%s%s>%s</A>\n", @sortnum[$cnt], $FTPURLPRE, @sortdata[$cnt], @sortdata[$cnt];
}

# finish HTML report

printf HTMLFILE "<HR>Created with wu-ftpd-log.pl by <A HREF=\"http://www.hvu.nl/~koos\">Koos van den Hout</A>.\n";
printf HTMLFILE "</BODY>\n</HTML>\n<!--Created with wu-ftpd-log.pl-->\n";

# finish report

printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Files : %u\n",$yesterdayanonulfiles;
printf REPORT "Bytes : %u\n",$yesterdayanonulbytes;
printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Outgoing anonymous traffic :\n";
printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Files : %u\n",$yesterdayanondlfiles;
printf REPORT "Bytes : %u\n",$yesterdayanondlbytes;
printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Outgoing realuser traffic :\n";
printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Files : %u\n",$yesterdayuserdlfiles;
printf REPORT "Bytes : %u\n",$yesterdayuserdlbytes;
printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Incoming realuser traffic :\n";
printf REPORT "-------------------------------------------------------------\n";
printf REPORT "Files : %u\n",$yesterdayuserulfiles;
printf REPORT "Bytes : %u\n",$yesterdayuserulbytes;
printf REPORT "-------------------------------------------------------------\n";

#thatsit

