#!/usr/bin/perl
#
# This code is distributed under the terms of the GPL
#
# (c) 2006 marco.s
#
# $Id: checkup,v 1.0 2006/08/30 00:00:00 marco.s Exp $
#

use strict;

use IO::Socket;
use HTTP::Date;

my $swroot='/var/ipfire';
my $scriptpath=substr($0,0,rindex($0,"/"));
my $apphome="/var/ipfire/updatexlrator";
my $logfile="/var/log/updatexlrator/checkup.log";
my $debug=(-e "$apphome/debug");
my $repository='/srv/web/ipfire/html/updatecache';
my %xlratorsettings=();
my $download=0;
my $updatefile='';
my $sourceurl='';
my $remote_size=0;
my $local_size=0;
my $remote_mtime=0;
my $local_mtime=0;
my @updatelist=();
my @metadata=();

@updatelist = <$repository/*>;

my $sfUnknown  = "0";
my $sfOk       = "1";
my $sfOutdated = "2";

if (-e "$swroot/updatexlrator/settings")
{
	&readhash("$swroot/updatexlrator/settings", \%xlratorsettings);
	if ($xlratorsettings{'FULL_AUTOSYNC'} eq 'on') { $download=1; };
}

foreach (@updatelist)
{
	if (!-d $_)
	{
		$updatefile = substr($_,rindex($_,"/")+1);
		if (-e "$repository/metadata/$updatefile")
		{
			open (FILE,"$repository/metadata/$updatefile");
			@metadata = <FILE>;
			close FILE;
			chomp(@metadata);
			$sourceurl = $metadata[0];

			$remote_size = &getdownloadsize($sourceurl);
			$local_size = (-s "$repository/$updatefile");

			$remote_mtime = &getlastmod($sourceurl);
			$local_mtime = &getmtime("$repository/$updatefile");

			if ($remote_mtime eq 0)
			{
				$metadata[2] = $sfUnknown;
				if ($debug) { &writelog("$updatefile - WARNING: Source not found"); }
				print "$updatefile - WARNING: Source not found\n";
			}
			elsif (($local_mtime eq $remote_mtime) && ($local_size == $remote_size))
			{
				$metadata[2] = $sfOk;
				$metadata[3] = time;
				if ($debug) { &writelog("$updatefile"); }
				print "$updatefile\n";
			}
			else
			{
				$metadata[2] = $sfOutdated;
				$metadata[3] = time;
				if ($debug) { &writelog("$updatefile - WARNING: Out of date"); }
				print "$updatefile - WARNING: Out of date\n";
				if ($download)
				{
					if ($debug)
					{
						1 while $remote_size =~ s/^(-?\d+)(\d{3})/$1.$2/;
						print "Please wait, retrieving file ($remote_size Byte) from source ...";
						`$scriptpath/../bin/wget -nd -nv -O $repository/$updatefile $sourceurl >>$logfile 2>&1`;
						print "\n";
					} else
					{
						`$scriptpath/../bin/wget -nd -nv -O $repository/$updatefile $sourceurl 2>&1`;
					}
					$local_mtime = &getmtime("$repository/$updatefile");
					if ($local_mtime eq $remote_mtime) { $metadata[2] = $sfOk; }
				}
			}
			open (FILE,">$repository/metadata/$updatefile");
			foreach (@metadata) { print FILE "$_\n"; }
			close FILE;
		}
	}
}

# -------------------------------------------------------------------

sub readhash
{
	my $filename = $_[0];
	my $hash = $_[1];
	my ($var, $val);

	if (-e $filename)
	{
		open(FILE, $filename) or die "Unable to read file $filename";
		while (<FILE>)
		{
			chop;
			($var, $val) = split /=/, $_, 2;
			if ($var)
			{
				$val =~ s/^\'//g;
				$val =~ s/\'$//g;

				# Untaint variables read from hash
				$var =~ /([A-Za-z0-9_-]*)/; $var = $1;
				$val =~ /([\w\W]*)/; $val = $1;
				$hash->{$var} = $val;
			}
		}
		close FILE;
	}
}

# -------------------------------------------------------------------

sub getmtime
{
        my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($_[0]);

        return $mtime;
}

# -------------------------------------------------------------------

sub getlastmod
{
	my $remote=0;
	my @response=();
	my $lastmoddate=0;

	my $url = $_[0];

	$url =~ s@^(.*)://([^/]*)@@;

	my $proto = $1;
	my $fqhn  = $2;

	if ((-e "$swroot/red/active") && ($proto eq 'http'))
	{
		$remote = IO::Socket::INET->new(
			PeerHost => $fqhn,
			PeerPort => 'http(80)',
			Timeout  => 1
		);
	}

	if ($remote)
	{
		print $remote "HEAD $url HTTP/1.0\n";
		print $remote "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\n";
		print $remote "Host: $fqhn\n";
		print $remote "Accept: */*\n\n";
		while (<$remote>) { push(@response,$_); }
		close $remote;
		if ($response[0] =~ /^HTTP\/\d+\.\d+\s\d+\sOK\s*$/)
		{
			foreach (@response)
			{
				if (/^Last-Modified: /i)
				{
					s/^Last-Modified: //i;
					$lastmoddate=HTTP::Date::str2time($_);
				}
			}
		}
	}
	return $lastmoddate;
}

# -------------------------------------------------------------------

sub getdownloadsize
{
	my $remote=0;
	my @response=();
	my $contentlength=0;

	my $url = $_[0];

	$url =~ s@^(.*)://([^/]*)@@;

	my $proto = $1;
	my $fqhn  = $2;

	if ((-e "$swroot/red/active") && ($proto eq 'http'))
	{
		$remote = IO::Socket::INET->new(
			PeerHost => $fqhn,
			PeerPort => 'http(80)',
			Timeout  => 1
		);
	}

	if ($remote)
	{
		print $remote "HEAD $url HTTP/1.0\n";
		print $remote "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\n";
		print $remote "Host: $fqhn\n";
		print $remote "Accept: */*\n\n";
		while (<$remote>) { push(@response,$_); }
		close $remote;
		if ($response[0] =~ /^HTTP\/\d+\.\d+\s\d+\sOK\s*$/)
		{
			foreach (@response)
			{
				if (/^Content-Length: /i)
				{
					s/^Content-Length: //i;
					$contentlength=int($_);
				}
			}
		}
	}
	return $contentlength;
}

# -------------------------------------------------------------------

sub writelog
{
        open (LOGFILE,">>$logfile");
        my @now = localtime(time);
        printf LOGFILE "%02d:%02d:%02d %s\n",$now[2],$now[1],$now[0],$_[0];
        close LOGFILE;
}

# -------------------------------------------------------------------
