package syslogd;

use warnings;
use strict;

use IO::Socket;
use Data::Dump qw/dump/;
use CouchDB;
use File::Slurp;

use server;

our $port = 514;
our $MAXLEN = 1524;

sub message {
	my $sock = shift;

	my $buf;
	$sock->recv($buf, $MAXLEN);

	next unless $buf;

	my ($port, $ipaddr) = sockaddr_in($sock->peername);
	my $log = {
		ip => join('.', unpack('C4',$ipaddr)),
		buf => $buf,
	};

	if ( $buf =~ s/<(\d+)>// ) {
		$log->{pri}    = $1 % 8;
		$log->{facility} = ( $1 - $log->{pri} ) / 8;
	
		$log->{timestamp} = $1 if $buf =~ s/^(\w\w\w\s+\d+\s+\d\d:\d\d:\d\d)\s*//;	# strip timestamp which some syslog servers insert here

		if ( $buf =~ s/^([^:]+)\s*:\s*// ) {
			my $tag = $1;
			if ( $tag =~ m{^(\S+)\s(\S+)} ) {
				$log->{tag} = $2;
				$log->{hostname} = $1;
			} else {
				$log->{tag} = $tag;
			}

			if ( $log->{tag} =~ s/\[(\d+)\]$// ) {
				$log->{pid} = $1;
			} elsif ( $buf =~ s/^(\d+):\s*// ) {
				$log->{pid} = $1;
			}
		}

		$log->{tag} =~ s{^/.+/([^/]+)$}{$1};

		if ( $log->{tag} =~ m{CRON}i && $buf =~ m{^\((\w+)\) (.+) \((.+)\)$} ) {
			$log->{cron} = {
				user => $1,
				command => $2,
				argument => $3,
			};
		}

		if ( $buf =~ m{(init|error|mount|smart|usb|fs)}i ) {
			$log->{category} = $1;
		}

		$log->{message} = $buf;
	}

	warn "log ",dump( $log );
	CouchDB::audit( $log->{tag}, $log );
}

sub start {

	my $sock = IO::Socket::INET->new(
		LocalPort => $port,
		Proto => 'udp',
		ReuseAddr => 1,
	) || die "can't listen to $port: $!";

	CouchDB::audit('start', { port => $port });

	while(1) {
		message($sock);
		server->refresh;
	}
}

sub install_local {
	my $rsyslog = '/etc/rsyslog.d';
	return unless -d $rsyslog;
	$rsyslog .= '/pxelator.conf';
	warn "# redirect local syslog to pxelator using $rsyslog";
	write_file $rsyslog, "*.*\t\@$server::ip\n";
	system "( /etc/init.d/rsyslog stop ; sleep 2 ; /etc/init.d/rsyslog start ; rm $rsyslog ) &";
}

1;
