:
eval 'exec perl -wS $0 ${1+"$@"}'
    if 0;
#**************************************************************
#  
#  Licensed to the Apache Software Foundation (ASF) under one
#  or more contributor license agreements.  See the NOTICE file
#  distributed with this work for additional information
#  regarding copyright ownership.  The ASF licenses this file
#  to you under the Apache License, Version 2.0 (the
#  "License"); you may not use this file except in compliance
#  with the License.  You may obtain a copy of the License at
#  
#    http://www.apache.org/licenses/LICENSE-2.0
#  
#  Unless required by applicable law or agreed to in writing,
#  software distributed under the License is distributed on an
#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#  KIND, either express or implied.  See the License for the
#  specific language governing permissions and limitations
#  under the License.
#  
#**************************************************************



use strict;
use Getopt::Long;

my $debug = 0;
my $max_files = 20; 		  # sign $max_files with one command line

#### globals #####
my $myname 		= "";
my $opt_dir 	= "";
my $opt_exclude = "";         # file with a list of not signable dll and exe files
my $opt_verbose = 0;
my $opt_help	= 0;
my $opt_log		= "";		  # for logging
my $opt_pass	= "";         # password for signing
my $opt_pfxfile = "";		  # Personal Information Exchange file
my $opt_timestamp_url = "";   # timestamp url
my %exclude_files = ();  	  # list of not signable dll and exe files
my $signtool    = "signtool.exe sign";
my @args		= ();
my @files_to_sign = ();

#### main #####
$myname = script_id();
if ( $#ARGV < 2 ) {
	usage();
    exit(1);
}
@args = parse_options();
get_exclude_files();
@files_to_sign = get_files(\@args);
if ( $opt_log ) {               # logging
	open(LOG,">$opt_log") || die "Can't open log file $opt_log\n";
}
sign_files(\@files_to_sign);
close LOG if ($opt_log);        # logging
exit 0;


#### subroutines ####

sub script_id
{
    ( my $script_name = $0 ) =~ s/^.*[\\\/]([\w\.]+)$/$1/;

    my $script_rev;
    my $id_str = ' $Revision$ ';
    $id_str =~ /Revision:\s+(\S+)\s+\$/
      ? ($script_rev = $1) : ($script_rev = "-");
#    print "\n$script_name -- version: $script_rev\n";
    return $script_name;
}

############################################################################
sub parse_options		#09.07.2007 08:13
############################################################################
{
	# e exclude list file
	# v verbose
    my $filelist_filename = undef;
	my $success = GetOptions('h' => \$opt_help,
         'd=s' => \$opt_dir, 'e=s'=>\$opt_exclude, 'f=s'=>\$opt_pfxfile, 'l=s'=>\$opt_log,
		 'p=s'=>\$opt_pass,'v'=>\$opt_verbose, 't=s'=>\$opt_timestamp_url, 'i=s'=>\$filelist_filename);
    if ( !$success || $opt_help ) {
        usage();
        exit(1);
    }
	if ( !$opt_exclude || !$opt_pfxfile || !$opt_pass || !$opt_timestamp_url) {
		print "ERROR: Parameter missing!\n!";
        usage();
        exit(1);
	}

    # Read the names of files to sign from the given file.
    die "no list of files given" unless defined $filelist_filename;
    open my $in, $filelist_filename;
    my @filelist = ();
    while (<$in>)
    {
        chomp($_);
        push @filelist, $_;
    }
	return @filelist;
}	##parse_options

############################################################################
sub get_exclude_files		#09.07.2007 10:12
############################################################################
{
	if ( -e $opt_exclude ) {
            # get data from cache file
            open( IN, "<$opt_exclude") || die "Can't open exclude file $opt_exclude\n";
            while ( my $line = <IN> ) {
			chomp($line);
			$exclude_files{$line} = 1;			# fill hash
			print "$line - $exclude_files{$line}\n" if ($debug);
            }
        } else
        {
			print_error("Can't open $opt_exclude file!\n");
		}
}	##get_exclude_files

############################################################################
sub get_files		#10.07.2007 10:19
############################################################################
 {
	use File::Basename;
    my $target = shift;
	my $file_pattern;
	my $file;
	my @files = ();
	print "\n";
	foreach $file_pattern ( @$target )
	{
		print "Files: $file_pattern\n";
        foreach $file ( glob( $file_pattern ) )
		{
            my $lib = File::Basename::basename $file;
			if ( ! $exclude_files{$lib} ) {
				push @files,$file;
			}
			else
			{
				print "exclude=$lib\n" if ($opt_verbose);
			}
		}
	}
	print "\n";
	return @files;
}	##get_files

############################################################################
sub sign_files		#09.07.2007 10:36
############################################################################
{
	my $files_to_sign = shift;
	my $commandline_base = ""; # contains whole stuff without the file name
	my $file = "";
	my $result = "";

	print_error("Can't open PFX file: $opt_pfxfile\n") if ( ! -e $opt_pfxfile );
	print_error("Password is empty\n") if ( !$opt_pass );
	if ( $opt_pass =~ /\.exe$/ ) {
		# get password by tool
		open(PIPE, "$opt_pass 2>&1 |") || die "Can't open PIPE!\n";
		my $pass = <PIPE>;
		close PIPE;
		print_error("Can't get password!\n") if ( !$pass ); # exit here
		$opt_pass = $pass;
	}
	$signtool .= " -v" if ($opt_verbose);
	$commandline_base = $signtool . " " . "-f $opt_pfxfile -p $opt_pass -t $opt_timestamp_url";

	# Here switch between:
	# one command line for muliple files (all doesn't work, too much) / for each file one command line
	if ( $max_files > 1 ) {
		exec_multi_sign($files_to_sign, $commandline_base);
	} else
	{
		exec_single_sign($files_to_sign, $commandline_base);
	}
}	##sign_files

############################################################################
sub exec_single_sign		#11.07.2007 09:05
############################################################################
{
	my $files_to_sign    = shift;
	my $commandline_base = shift; 				  # contains whole stuff without the file name
	my $file = "";
	my $commandline = "";

	foreach $file (@$files_to_sign)
	{
		$commandline = $commandline_base . " $file";
		print "$commandline\n" if ($debug);
		execute($commandline);
	} #foreach
}	##exec_single_sign

############################################################################
sub exec_multi_sign		#11.07.2007 08:56
############################################################################
 {
	# sign multiple file with one command line
	my $files_to_sign    = shift;
	my $commandline_base = shift; 				  # contains whole stuff without the file name
	my $commandline = $commandline_base;	      # contains stuff which will be executed
	my $file = "";
	my $counter = 0;

	foreach $file (@$files_to_sign)
	{
		$commandline .= " $file";
		++$counter;
		if ( $counter >= $max_files ) {
			execute($commandline);
			$counter = 0;						 # reset counter
			$commandline = $commandline_base;    # reset command line
		}
	}
	execute($commandline) if ($counter > 0);
}	##exec_multi_sign

############################################################################
sub execute		#11.07.2007 10:02
############################################################################
{
	my $commandline = shift;
	my $result = "";

  	print "$commandline\n" if ($debug);
  	open(PIPE, "$commandline 2>&1 |") || die "Error: Cant open pipe!\n";
  	while ( $result = <PIPE> ) {
  		print LOG "$result" if ($opt_log);        # logging
  		if ( $result =~ /SignTool Error\:/ ) {
			close PIPE;
  			print_error( "$result\n" );
  		} # if error
  	} # while
  	close PIPE;
}	##execute

############################################################################
sub print_error		#09.07.2007 11:21
############################################################################
 {
	my $text = shift;
	print "ERROR: $text\n";
	print LOG "ERROR: $text\n" if ($opt_log);        # logging
	close LOG if ($opt_log);        				 # logging
	exit(1);
}	##print_error

############################################################################
sub usage		#09.07.2007 08:39
############################################################################
 {
	print "Usage:\t $myname <-e filename> <-f filename> <-p password> <-t timestamp> <-i filename> [-l filename] [-v]\n";
    print "Options:\n";
	print "\t -e filename\t\t\tFile which contains a list of files which don't have to be signed.\n";
    print                            "Mandatory.\n";
    print "\t -f pfx_filename\t\t\"Personal Information Exchange\" file. ";
    print                            "Mandatory.\n";
    print "\t -p password\t\t\tPassword for \"Personal Information Exchange\" file. Mandatory.\n";
    print "\t -t timestamp\t\t\tTimestamp URL e.g. \"http://timestamp.verisign.com/scripts/timstamp.dll\"\n";
    print "\t -i filename\t\t\tName of the file that contains the names of files to sign.\"\n";
    print "\t\t\t\t\tMandatory.\n";
	print "\t -l log_filename\t\tFile for logging.\n";
    print "\t -v\t\t\t\tVerbose.\n";
}	##usage
