package Yaala::Parser;

# Written by David Augros <david@lightship.net>

use strict;
use warnings;
use vars qw(%DATAFIELDS);

use Exporter;
use Yaala::Parser::WebserverTools qw#%MONTH_NUMBERS#;
use Yaala::Data::Persistent qw#init#;

@Yaala::Parser::EXPORT_OK = qw#%DATAFIELDS parse extra#;
@Yaala::Parser::ISA = ('Exporter');

our $LASTDATE = init ('$LASTDATE', 'scalar');
our $EXTRA = init ('$EXTRA', 'hash');

if (!$$LASTDATE) { $$LASTDATE = 0; }
if (!defined ($EXTRA->{'total'})) { $EXTRA->{'total'} = 0; }
if (!defined ($EXTRA->{'days'} )) { $EXTRA->{'days'}  = {}; }

our %severity = map
	{ $_ => 1 }
	(qw#kern user mail daemon auth syslog lpr
	news uucp cron authpriv ftp
	local0 local1 local2 local3
	local4 local5 local6 local7#);

%DATAFIELDS = (
	date		=> 'key:date',
	hour		=> 'key:hour',
	client		=> 'key:host',
	
	query		=> 'key',
	class		=> 'key',
	type		=> 'key',

	severity	=> 'key',
	category	=> 'key',
	
	requests	=> 'agg'
);

require Yaala::Data::Core;
import Yaala::Data::Core qw#store#;

my ($default_second, $default_minute, $default_hour, $default_day, $default_year) = (localtime ())[0,1,2,3,5];
my $default_month = (split (m/\s+/, scalar (localtime ())))[1];
$default_year += 1900;

my $VERSION = '$Id: Bind9.pm,v 1.4 2003/12/07 15:01:33 octo Exp $';
print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);

return (1);

sub parse
{
	my $line = shift or return undef;
	#if ($line =~ m/^(?:(\w{3}) (\d+) (\d\d)[\d:\.]+ )?(?:(\w+): )?(?:(\w+): )?client ([\d\.])#\d+: query: (\S+) (\S+) (\S+)$/)
	if ($line =~ m/^(?:(\w{3}) (\d+) (\d\d):(\d\d):(\d\d)\.(\d\d\d) )?(?:(\w+): )?(?:(\w+): )?client ([\d\.]+)#\d+: query: (\S+) (\S+) (\S+)$/)
	{
		my ($client, $query, $class, $type) = ($9, $10, $11, $12);

		my ($month, $day, $hour, $minute, $second, $frac) =
		(
			$default_month, $default_day, $default_hour,
			$default_minute, $default_second, '000'
		);
		
		if (defined ($1) and $1)
		{
			($month, $day, $hour, $minute, $second, $frac) = ($MONTH_NUMBERS{$1},
				$2, $3, $4, $5, $6);

			print STDERR $/, __FILE__, ": $1" if (!$month);
			
			my $tmp = int (sprintf ("%04u%02u%02u%02u%02u%02u%03u",
					$default_year, $month, $day, $hour,
					$minute, $second, $frac));

			if ($tmp < $$LASTDATE) 
			{
				print STDERR $/, __FILE__, ": Skipping.. ($tmp < $$LASTDATE)" if ($::DEBUG & 0x0200);
				return (undef); 
			}
			else { $$LASTDATE = $tmp; }
		}

		my $date = sprintf ("%04u-%02u-%02u",
			$default_year, $month, $day);

		my $category = '*UNKNOWN*';
		my $severity = '*UNKNOWN*';
		if (defined ($7) and $7 and defined ($8) and $8)
		{
			$category = $7;
			$severity = $8;
		}
		elsif (defined ($7) and $7)
		{
			if (defined ($severity{$7})) { $severity = $7; }
			else { $category = $7; }
		}
		elsif (defined ($8) and $8)
		{
			if (defined ($severity{$8})) { $severity = $8; }
			else { $category = $8; }
		}

		if ($query =~ m/in-addr\.arpa$/)
		{
			my @tmp = reverse (split (m/\./, $query));
			splice (@tmp, 0, 2);

			$query = join ('.', @tmp);
		}
			
		$EXTRA->{'total'}++;
		$EXTRA->{'days'}{$date}++;

		my %combined = (
			date		=> $date,
			hour		=> $hour,
			client		=> $client,
	
			query		=> $query,
			class		=> $class,
			type		=> $type,
			
			severity	=> $severity,
			category	=> $category,

			requests	=> 1
		);

		store (\%combined);
	}
	elsif ($::DEBUG)
	{
		chomp ($line);
		print $/, __FILE__, ": Unable to parse: $line";
	}
}

sub extra
{
	my ($average, $days) = (0, 1);
	
	return (0) unless ($EXTRA->{'total'});
	
	$days = scalar (keys (%{$EXTRA->{'days'}}));
	
	$::EXTRA->{'Total requests'} = $EXTRA->{'total'};
	$::EXTRA->{'Average requests per day'} = sprintf ("%.1f", $EXTRA->{'total'} / $days);;
	$::EXTRA->{'Reporting period'} = "$days days";
}
