#!/usr/bin/perl 

# automatically builds debian packages containing clamav data files

# Written by Marc Haber <mh+debian-packages@zugschlus.de>
# using code by Hilko Bengen and Christoph Biedl
# perl help by Marc Brockschmidt

use strict;
use warnings;
use English;
use File::Glob;
use File::stat;
use Date::Parse;
use DateTime;
use IPC::Run3;
use IO::Select;

my $FRESHCLAM=$ENV{"FRESHCLAM"} || `which freshclam`; ##+# do this better?
my $FRESHCLAMCONF=$ENV{"FRESHCLAMCONF"} || "";
my $SIGTOOL=$ENV{"SIGTOOL"} || `which sigtool`; ##+# do this better?
my $CLAMAV_CHECK=$ENV{"CLAMAV_CHECK"} || `which clamav-check`; ##+# do this better
my $DEBHELPERVERSION=$ENV{"DEBHELPERVERSION"} || "5";
my $DISTRIBUTION=$ENV{"DISTRIBUTION"} || "local";
my $SECTION=$ENV{"SECTION"} || "utils";
my $AUTOGENWARNING=$ENV{"AUTOGENWARNING"} || ".
 Please note that this package was built automatically without human
 supervision and was only automatically checked before upload. Use
 at your own risk.";

chomp $FRESHCLAM;
chomp $SIGTOOL;
chomp $CLAMAV_CHECK;

if( "$AUTOGENWARNING" eq "none" ) {
    $AUTOGENWARNING="";
}

package Debian::Package::Make::ClamavData;

use Debian::Package::Make::TemplateDir;
our @ISA = qw(Debian::Package::Make::TemplateDir);

#sub cmd3sel {
#    my (%param) = @_;
#    my $pid = IPC::Open3::open3(*CMD_IN, *CMD_OUT, *CMD_ERR, @{$param{cmd}});
#    my $exit = 0;
    
#    $SIG{CHLD} = sub {
#	$exit = $? if waitpid($pid,0)>0;
#    };
#    close(CMD_IN);
    
#    my $selector = IO::Select->new();
#    $selector->add(*CMD_ERR, *CMD_OUT);
    
#    while (my @ready = $selector->can_read) {
#	foreach my $fh (@ready) {
#	    if( fileno($fh) == fileno(CMD_ERR) ) {
#	        ${$param{stderr}}.=<CMD_ERR>;
#	    }
#	    else
#	    {
#	        ${$param{stdout}}.=<CMD_OUT>;
#	    }
#	    $selector->remove($fh) if eof($fh);
#	}
#    }    
#    close(CMD_OUT);
#    close(CMD_ERR);
#    return $exit>>8;
#}

sub new {
    my ($class, %param) = @_;
    $param{me} ||= 'Marc Haber <mh+debian-packages@zugschlus.de>';
    $param{section} ||= "$SECTION";
    $param{distribution} ||= "$DISTRIBUTION";
    $param{source} ||= 'clamav-data';
    
    $class->SUPER::new(%param);
}

sub detect_version {
    my ($self, %param) = @_;
    
    my (@out, $err);
    # obtain data from daily.cvd in order to build package version number
    IPC::Run3::run3(["$SIGTOOL","--stdout","--info=$self->{build_dir}/daily.cvd"],
	\undef,\@out,\$err)
      or die "cannot run $SIGTOOL on $self->{build_dir}/daily.cvd: $! ($err)\n";
    print "sigtool output:\n@out\n";
    my ($unpdate,$pdate,$dt,$date,$vers,$pkgvers);
    ($unpdate)=grep(/^Build time:\s/, @out);
    $unpdate =~ s/^Build time:\s+(\d+)/$1/;
    $pdate = Date::Parse::str2time($unpdate);
    $dt = DateTime->from_epoch(epoch=>$pdate);
    $date = $dt->ymd('').".".$dt->hms('');
    ($vers)=grep(/^Version:\s/, @out);
    chomp $vers;
    $vers =~ s/^Version:\s+(\d+)/$1/;
    $pkgvers = "$date.$vers";
    if( defined $ENV{"VERSSUFFIX"} ) {
	$pkgvers .= $ENV{"VERSSUFFIX"};
    }
    print "pkgvers $pkgvers:\n";
    $self->version("$pkgvers");
}

sub generate_build_dir {
    my ($self, %param) = @_;
    $self->SUPER::generate_build_dir(%param);

    if( defined $param{srcdir} ) {
    
	my (@out, $err);
	
	# copy files from given dir
	IPC::Run3::run3(["cp","-r",File::Glob::bsd_glob("$param{srcdir}/*"),"$self->{build_dir}"],\undef,\undef,\$err)
	  or die "cannot copy $param{srcdir}/* to orig dir: $! ($err)\n";
    } else {
	chmod oct(770), $self->{build_dir};
	
	my $freshclamconfigfile;
	
	$freshclamconfigfile="";
	if ( "$FRESHCLAMCONF" ne "" ) {
	    $freshclamconfigfile="--config-file=$FRESHCLAMCONF";
	}
	
	my (@out, $err);
	if( ! IPC::Run3::run3(["$FRESHCLAM","$freshclamconfigfile","--quiet","--user",getpwuid($main::EUID),"--datadir","$self->{build_dir}","--log","$self->{build_dir}/freshclam.log","--log-verbose","--on-update-execute","touch $self->{build_dir}/freshclam-new"],\undef,\@out,\$err) ) {
	    print STDERR @out, $err;
	    print STDERR "ERR: can't download data files, error running freshclam: $?\n";
	}
	unlink "$self->{build_dir}/mirrors.dat";
	print @out, $err;
	if( ! -e "$self->{build_dir}/freshclam-new" ) {
	    print "No new databases available\n";
	    $self->cleanup;
	    exit 10;
	}
	unlink "$self->{build_dir}/freshclam.log", "$self->{build_dir}/freshclam-new";
    }
    $self->detect_version();
}

sub check_databases {
    my ($self, $param) = @_;
    my (@out, $err);
    
    # check databases
    $ENV{"CLAMSCAN_OPTS"}="-d $self->{build_dir}";
    IPC::Run3::run3(["$CLAMAV_CHECK",""],\undef,\@out,\$err);
    print @out, $err, "CHILD_ERROR: $main::CHILD_ERROR\n";
    ##+# undefine $ENV{"CLAMSCAN_OPTS"}?
    if( $main::CHILD_ERROR != 0 ) {
	exit $main::CHILD_ERROR;
    }
}

sub prepare_files {
    my ($self, %param) = @_;
    $self->SUPER::prepare_files(%param);

    $self->{files}{"debian/control"} =~ s/#DEBHELPERVERSION#/$DEBHELPERVERSION/g;
    $self->{files}{"debian/control"} =~ s/#AUTOGENWARNING#/$AUTOGENWARNING/g;
}

1;

package main;

use Cwd;
use Getopt::Long;

my ($dir);
my $r = GetOptions('dir=s' => \$dir);

my $pg = Debian::Package::Make::ClamavData->new();

$pg->generate_build_dir(srcdir=>$dir);

$pg->check_databases;

print "Build directory: $pg->{base_dir}\n";

$pg->prepare_files( template_dir => '/usr/share/clamav-getfiles/clamav-data.template' );
$pg->generate_files;
$pg->build;
$pg->copy_files;
$pg->cleanup;

1;
