#
# $Id: SyslogLine.pm,v 1.4 2002/03/14 10:14:11 fpmip Exp $
#

# Author : Tycho Fruru <tycho@fruru.com>

# Copyright (C) 2001 Tycho Fruru <tycho@fruru.com>
# Copyright (C) 2001 Conostix S.A. Luxembourg - Tycho Fruru <tycho@conostix.com>

# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#

package IPFC::Parse::Transport::SyslogLine;

use strict;
use warnings;
use IPFC::Log;

use Time::Local;

my %months=
	('jan'=>0,'feb'=>1,'mar'=>2,'apr'=>3,'may'=>4,'jun'=>5,
	 'jul'=>6,'aug'=>7,'sep'=>8,'oct'=>9,'nov'=>10,'dec'=>11);

sub parse($$$) {
	shift; # current class
	my $entry = shift;
	my $function_name = shift;
	my $template_event = shift;
	
	my $current_entry;
	my $index = 0;
	my $rc = 1;

	my $eventgroup = IPFC::EventGroup->new;
		
#	IPFC::Log::logger(1,"Starting process_transport_syslog_line");
	
	while (($rc == 1) and (defined($entry->{'syslog-line'}->[$index]))) {
		my $event = $template_event->clone;
		my $decoded_line = main::decode_entry($entry->{'syslog-line'}->[$index]);
		
		my $attrib;
		my $log_message = $decoded_line;
		
		$event->replace_attributes({'message' => $decoded_line});

# our adapted syslog daemon logs facility and level before the syslog message
		if ($decoded_line =~ /^(\w+):(\w+) (.*)$/) {
			$attrib->{'syslog_facility'} = $1;
			$attrib->{'syslog_priority'} = $2;
			$decoded_line = $3;
		}
		
		if ($decoded_line =~ /^\s*(\d*): (.*)$/) {
			$decoded_line = $2;
		}
		
		if ($decoded_line =~ /^\s*(\w+\s+\d+\s+\d+:\d+:\d+)\s+(\w+)\s+(([^:]+)\:)?\s*(\w*.*)$/) {
# Mar  4 17:41:20 herodot su(pam_unix)[32254]: session closed for user dbwrapnet

			$attrib->{'syslog_date'} = $1;
			$attrib->{'host'} 	 = $2;
			if (defined($4)) {
			  $attrib->{'logging_program'} = $4;
			}

			$log_message = $5;
		} elsif ($decoded_line =~ /^\s*(\w+\s+\d+\s+\d+:\d+:\d+\s+\w+):\s+%([^:]+):\s+(.*)$/) {
# Mar  6 11:38:45 CET: %SEC-6-IPACCESSLOGP: list consultant denied tcp 192.168.84.32(2785) -> 209.10.17.133(80), 3 packets
			$attrib->{'syslog_date'}     = $1;
			$attrib->{'logging_program'} = $2;
			$log_message = $3;
		}
		
		if (defined($attrib->{'logging_program'}) && $attrib->{'logging_program'} =~ /^(.+)\[(\d+)\]$/) {
			$attrib->{'logging_program'} = $1;
			$attrib->{'process_id'} = $2;
		}
		
		if (defined($attrib->{'syslog_date'}) && $attrib->{'syslog_date'} =~ /^(\w+)\s+(\d+)\s+(\d+:\d+:\d+)(\s+\w+)?$/) {
			my $syslog_month = lc($1);
			my $syslog_day = $2;
			my $syslog_time = $3;
			my $syslog_timezone = $4;
		
		# heuristic to get the right year (which is not included in syslog lines !)
		# try the current year, one year ahead and one year behind
		# the date which is the nearest from the current one is supposed to be the right one
		
			my ($sec,$min,$hour,$mday,$current_mon,$current_year,$wday,$yday) =
                        	                                   gmtime(time);
							   
			$current_year+=1900; # use the correct 4 digit version
		
			$syslog_month = $months{$syslog_month};
			if (!$syslog_month) { $syslog_month = 0 };
		
			my $current_seconds = time;
			my $syslog_current_year = Time::Local::timegm(0,0,0,$syslog_day,$syslog_month,$current_year);
			my $syslog_next_year = Time::Local::timegm(0,0,0,$syslog_day,$syslog_month,$current_year+1);
			my $syslog_previous_year = Time::Local::timegm(0,0,0,$syslog_day,$syslog_month,$current_year-1);
		
			my $difference_current = abs($current_seconds - $syslog_current_year);
		
			my $difference_next = abs($current_seconds - $syslog_next_year);
			my $difference_previous = abs($current_seconds - $syslog_previous_year);
		
			my $guessed_year;
		
			if (($difference_current < $difference_next) &&
			    ($difference_current < $difference_previous)) {
				$guessed_year = $current_year;
			} elsif ($difference_previous < $difference_next) {
				$guessed_year = $current_year-1;
			} else {
				$guessed_year = $current_year+1;
			}
		
			$syslog_month+=1; # to get back to human months
			
			if (defined($syslog_timezone)) {
				$attrib->{'time'}="$guessed_year-$syslog_month-$syslog_day $syslog_time $syslog_timezone";
			} else {
				$attrib->{'time'}="$guessed_year-$syslog_month-$syslog_day $syslog_time";
			}
		}
		
		$event->add_attributes($attrib);
		my $result_event = $function_name->parse($log_message,$event);
		if (!defined $result_event) {
			return undef;
		}
		delete $entry->{'syslog-line'}->[$index];
		$eventgroup->add_event($result_event);

		$index++;
	}
	
#	IPFC::Log::logger(5,"return value for process_transport_syslog_line : $rc\n");
	return $eventgroup;
}

return 1;
