#!/usr/bin/perl

use POSIX qw(tmpnam);
use sigtrap qw(handler quit normal-signals);
use IO::File;
use IO::Handle;
use GnuPG::Interface;
use GnuPG::Handles;
use strict;

use vars qw($filename $tempfile $group $gnupg @recipients $pubkeydir);

# the group the file should be chowned to:
$group = "wheel";

# the directory where we'll dump our pub keys
$pubkeydir = "/usr/local/share/gpgkeys";

# people that the file should be encrypted for
@recipients = qw(email@address.com another@address.com);

# default filename
$filename = "/root/export.csv.gpg";

# filename can be specified on the command line
if ($ARGV[0] and -e $ARGV[0]) { $filename = $ARGV[0] }
$tempfile = tmpnam;
umask 0007;
#umask 0077;

#$BOLD="[0;0;1m";
#$NORMAL="[0m";

system("stty -echo");
my $passphrase = undef;
print "Enter your default key passphrase: "; chomp($passphrase = <STDIN>);
system("stty echo");

my $gnupg = GnuPG::Interface->new();
$gnupg->options->hash_init(armor => 1, homedir => $ENV{HOME} . "/.gnupg", always_trust => 1 );
$gnupg->passphrase($passphrase);
$gnupg->options->meta_interactive(0);

if ($gnupg->test_default_key_passphrase()) {
  print "good password.\n";
}
else {
  print "password failed.\n"; exit 1;
}

# dump sigs to $pubkeydir
&export_keys();
&import_keys();
&list_sigs();

my %stats = ();
$stats{passphrase} = [ stat($filename) ];

&decrypt();

if (not -e $tempfile) { print "\nDecryption failed.\n"; &quit }

unless (length $ENV{EDITOR}) { $ENV{EDITOR} = "vi" }
$stats{orig_tempnam} = [ stat($tempfile) ];
system("$ENV{EDITOR} $tempfile");
system("clear");
$stats{new_tempnam} = [ stat($tempfile) ];

if ($stats{new_tempnam}[9] == $stats{orig_tempnam}[9]) { 
  print "$tempfile is unchanged,  not updating.\n" 
}
else {
  $stats{passphrase_now} = [ stat($filename) ];
  unless ($stats{passphrase_now}[9] == $stats{passphrase}[9]) { 
    print "$filename has changed since you began editing.\n"
      . "Overwrite newer file? (y/n) ";
    my $this = <STDIN>;
    if ($this =~ /y/i) { &save }    
    else { print "Aborting.\n"; &quit; }
  }
  else { &encrypt($tempfile, $filename, $gnupg) }
}
  
&quit;
  
sub quit {
    if (-e $tempfile) { unlink <$tempfile\*> }
    exit;
}

sub encrypt {
  rename ($filename, $filename . "~");

  my $infile = new IO::File;
  $infile->open($tempfile, "r") or die $!;
  my $outfile = new IO::File;
  $outfile->open($filename, "w", 0660) or die $!;
  my $nullfile = new IO::File;
  $nullfile->open("/dev/null", "w") or die $!;

  my $handles = GnuPG::Handles->new( stdin  => $infile, 
                                     stdout => $outfile,
#                                     stderr => $nullfile,
                                   );

  foreach my $key (qw(stdin stdout stderr)) { $handles->options($key)->{direct} = 1; }

  foreach my $recipient (@recipients) {
    $gnupg->options->push_recipients($recipient);
  }

  my $pid = $gnupg->encrypt( handles => $handles );
  waitpid $pid, 0;
  close $outfile;
  close $infile;
  close $nullfile;

  if ($? != 0) {
    print "GPG encryption failed.  Reverting to original file.\n";
    rename ($filename . "~", $filename);
  }
  else { print "GPG encryption to $filename successful.\n" }

  chownfile($filename);
}

sub import_keys {

  my $nullfile = new IO::File;
  $nullfile->open("/dev/null", "w") or die $!;

  for my $keyfile (<$pubkeydir/*>) {

    my $infile = new IO::File;
    $infile->open($keyfile, "r") or die $!;
    my $handles = GnuPG::Handles->new(stdin => $infile, stdout => $nullfile, stderr => $nullfile);
    $handles->options("stdin")->{direct} = 1;
    my $pid = $gnupg->import_keys(handles => $handles);
    waitpid $pid, 0;
    close $infile;
  }

  close $nullfile;
}

sub list_sigs {

  # we will need to list and verify signatures here

#  my $pid = $gnupg->list_sigs(command_args => \@recipients);
  
}

sub export_keys {

  my $user = getpwuid($>);
  my $outfilename = "$pubkeydir/$user";
  my $outfile = new IO::File;
  $outfile->open("$outfilename", "w", 0666) or die $!;
  my $handles = GnuPG::Handles->new(stdout => $outfile);
  $handles->options("stdout")->{direct} = 1;

  my $pid = $gnupg->export_keys(
                                handles => $handles,
                                command_args => \@recipients);
  waitpid $pid, 0;
  close $outfile;

  chownfile($outfilename);
}

sub chownfile {
  my ($filename) = @_;
  my @grp = getgrnam($group);
  chown $>, $grp[2], $filename;
}

sub decrypt {
  my $infile = new IO::File;
  $infile->open($filename, "r") or die $!;
  my $outfile = new IO::File;
  $outfile->open($tempfile, "w", 0600) or die $!;
  my $nullfile = new IO::File;
  $nullfile->open("/dev/null", "w") or die $!;

  my $handles = GnuPG::Handles->new( stdin  => $infile, 
                                     stdout => $outfile,
#                                     stderr => $nullfile,
                                   );

  foreach my $key (qw(stdin stdout stderr)) { $handles->options($key)->{direct} = 1; }

  my $pid = $gnupg->decrypt( handles => $handles );
  waitpid $pid, 0;
  close $outfile;
  close $infile;
  close $nullfile;
}


