create caff configfile on first use
[pgp-tools.git] / caff / caff
index e77374037ab2ce0e5739bd252610c76e478df02f..35be431932aa20e283b390fb3599820552896a9b 100755 (executable)
--- a/caff/caff
+++ b/caff/caff
@@ -56,14 +56,22 @@ sigs and sigs done by you.
 
 =over
 
 
 =over
 
-=item B<-e>, B<--export>, B<-E>, B<--no-export>
+=item B<-e>, B<--export-old>
 
 
-Export/do not export old signatures. Default is to ask the user for each old
+Export old signatures. Default is to ask the user for each old signature.
+
+=item B<-E>, B<--no-export-old>
+
+Do not export old signatures. Default is to ask the user for each old
 signature.
 
 signature.
 
-=item B<-m>, B<--mail>, B<-M>, B<--no-mail>
+=item B<-m>, B<--mail>
+
+Send mail after signing. Default is to ask the user for each uid.
 
 
-Send/do not send mail after signing. Default is to ask the user for each uid.
+=item B<-M>, B<--no-mail>
+
+Do not send mail after signing. Default is to ask the user for each uid.
 
 =item B<-R>, B<--no-download>
 
 
 =item B<-R>, B<--no-download>
 
@@ -77,6 +85,10 @@ Do not sign the keys.
 
 Select the key that is used for signing, in case you have more than one key.
 
 
 Select the key that is used for signing, in case you have more than one key.
 
+=item B<--key-file> I<file>
+
+Import keys from file. Can be supplied more than once.
+
 =back
 
 =head1 FILES
 =back
 
 =head1 FILES
@@ -148,7 +160,7 @@ An additional keyid to encrypt messages to. Default: none.
 
 =item B<gpg-sign-args> [string]
 
 
 =item B<gpg-sign-args> [string]
 
-Additional arguments to pass to gpg. Default: none.
+Additional arguments to pass to gpg.  Default: none.
 
 =head2 Keyserver settings
 
 
 =head2 Keyserver settings
 
@@ -161,12 +173,21 @@ Keyserver to download keys from.  Default: B<subkeys.pgp.net>.
 If true, then skip the step of fetching keys from the keyserver.
 Default: B<0>.
 
 If true, then skip the step of fetching keys from the keyserver.
 Default: B<0>.
 
+=item B<key-files> [list of files]
+
+A list of files containing keys to be imported.
+
 =head2 Signing settings
 
 =item B<no-sign> [boolean]
 
 If true, then skip the signing step. Default: B<0>.
 
 =head2 Signing settings
 
 =item B<no-sign> [boolean]
 
 If true, then skip the signing step. Default: B<0>.
 
+=item B<ask-sign> [boolean]
+
+If true, then pause before continuing to the signing step.
+This is useful for offline signing. Default: B<0>.
+
 =item B<export-sig-age> [seconds]
 
 Don't export UIDs by default, on which your latest signature is older
 =item B<export-sig-age> [seconds]
 
 Don't export UIDs by default, on which your latest signature is older
@@ -245,9 +266,62 @@ my $REVISION = '$Rev$';
 my ($REVISION_NUMER) = $REVISION =~ /(\d+)/;
 my $VERSION = "0.0.0.$REVISION_NUMER";
 
 my ($REVISION_NUMER) = $REVISION =~ /(\d+)/;
 my $VERSION = "0.0.0.$REVISION_NUMER";
 
+sub generate_config() {
+       die "Error: \$LOGNAME is not set.\n" unless $ENV{LOGNAME};
+       my $gecos = (getpwnam($ENV{LOGNAME}))[6];
+       $gecos =~ s/,.*//;
+
+       my $gpg = GnuPG::Interface->new();
+       $gpg->call( 'gpg' );
+       $gpg->options->hash_init(
+               'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always --with-colons --fixed-list-mode } ] );
+       $gpg->options->meta_interactive( 0 );
+       my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
+       my $pid = $gpg->list_public_keys(handles => $handles, command_args => [ $gecos ]);
+       my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd);
+       waitpid $pid, 0;
+
+       if ($stdout eq '') {
+               warn ("No data from gpg for list-key\n"); # There should be at least 'tru:' everywhere.
+       };
+
+       my @keys;
+       unless (@keys = ($stdout =~ /^pub:[^r:]*:(?:[^:]*:){2,2}([^:]+):/mg)) {
+               die "Error: No keys were found using \"gpg --list-public-keys '$gecos'\".\n";
+       }
+       unless ($stdout =~ /^uid:.*<(.+@.+)>.*:/m) {
+               die "Error: No email address was found using \"gpg --list-public-keys '$gecos'\".\n";
+       }
+       my $email = $1;
+
+       return <<EOT;
+# .caffrc -- vim:syntax=perl:
+# This file is in perl(1) format - see caff(1) for details.
+
+\$CONFIG{'owner'}       = '$gecos';
+\$CONFIG{'email'}       = '$email';
+
+# you can get your long keyid from
+#   gpg --with-colons --list-key <yourkeyid|name|emailaddress..>
+#
+# if you have a v4 key, it will simply be the last 16 digits of
+# your fingerprint.
+
+\$CONFIG{'keyid'}       = [ qw{@keys} ];
+EOT
+};
+
 sub load_config() {
        my $config = $ENV{'HOME'} . '/.caffrc';
 sub load_config() {
        my $config = $ENV{'HOME'} . '/.caffrc';
-       -f $config or die "No file $config present.  See caff(1).\n";
+       unless (-f $config) {
+               print "No configfile $config present, I will use this template:\n";
+               my $template = generate_config();
+               print "$template\nPress enter to continue.";
+               <STDIN>;
+               open F, ">$config" or die "$config: $!";
+               print F $template;
+               close F;
+       }
        unless (scalar eval `cat $config`) {
                die "Couldn't parse $config: $EVAL_ERROR\n" if $EVAL_ERROR;
        };
        unless (scalar eval `cat $config`) {
                die "Couldn't parse $config: $EVAL_ERROR\n" if $EVAL_ERROR;
        };
@@ -258,7 +332,7 @@ sub load_config() {
        die ("keyid is not defined.\n") unless defined $CONFIG{'keyid'};
        die ("keyid is not an array ref\n") unless (ref $CONFIG{'keyid'} eq 'ARRAY');
        for my $keyid (@{$CONFIG{'keyid'}}) {
        die ("keyid is not defined.\n") unless defined $CONFIG{'keyid'};
        die ("keyid is not an array ref\n") unless (ref $CONFIG{'keyid'} eq 'ARRAY');
        for my $keyid (@{$CONFIG{'keyid'}}) {
-               $keyid =~ /^[A-Fa-z0-9]{16}$/ or die ("key $keyid is not a long (16 digit) keyid.\n");
+               $keyid =~ /^[A-F0-9]{16}$/i or die ("key $keyid is not a long (16 digit) keyid.\n");
        };
        @{$CONFIG{'keyid'}} = map { uc } @{$CONFIG{'keyid'}};
        $CONFIG{'export-sig-age'}= 24*60*60 unless defined $CONFIG{'export-sig-age'};
        };
        @{$CONFIG{'keyid'}} = map { uc } @{$CONFIG{'keyid'}};
        $CONFIG{'export-sig-age'}= 24*60*60 unless defined $CONFIG{'export-sig-age'};
@@ -269,6 +343,7 @@ sub load_config() {
        $CONFIG{'secret-keyring'} = $ENV{'HOME'}.'/.gnupg/secring.gpg' unless defined $CONFIG{'secret-keyring'};
        $CONFIG{'no-download'} = 0 unless defined $CONFIG{'no-download'};
        $CONFIG{'no-sign'} = 0 unless defined $CONFIG{'no-sign'};
        $CONFIG{'secret-keyring'} = $ENV{'HOME'}.'/.gnupg/secring.gpg' unless defined $CONFIG{'secret-keyring'};
        $CONFIG{'no-download'} = 0 unless defined $CONFIG{'no-download'};
        $CONFIG{'no-sign'} = 0 unless defined $CONFIG{'no-sign'};
+       $CONFIG{'key-files'} = () unless defined $CONFIG{'key-files'};
        $CONFIG{'mail-template'} = <<'EOM' unless defined $CONFIG{'mail-template'};
 Hi,
 
        $CONFIG{'mail-template'} = <<'EOM' unless defined $CONFIG{'mail-template'};
 Hi,
 
@@ -277,9 +352,13 @@ please find attached the user id{(scalar @uids >= 2 ? 's' : '')}.
     $OUT .= "\t".$uid."\n";
 };} of your key {$key} signed by me.
 
     $OUT .= "\t".$uid."\n";
 };} of your key {$key} signed by me.
 
-Note that I did not upload your key to any keyservers. If you want this
-new signature to be available to others, please upload it yourself.
-With GnuPG this can be done using
+Note that I did not upload your key to any keyservers.
+If you have multiple user ids, I sent the signature for each user id
+separately to that user id's associated email address. You can import
+the signatures by running each through `gpg --import`.
+
+If you want this new signature to be available to others, please upload
+it yourself. With GnuPG this can be done using
        gpg --keyserver subkeys.pgp.net --send-key {$key}
 
 If you have any questions, don't hesitate to ask.
        gpg --keyserver subkeys.pgp.net --send-key {$key}
 
 If you have any questions, don't hesitate to ask.
@@ -421,16 +500,35 @@ sub readwrite_gpg($$$$$%) {
 
 sub ask($$;$$) {
        my ($question, $default, $forceyes, $forceno) = @_;
 
 sub ask($$;$$) {
        my ($question, $default, $forceyes, $forceno) = @_;
-       return $default if $forceyes and $forceno;
-       return 1 if $forceyes;
-       return 0 if $forceno;
        my $answer;
        my $answer;
+       my $yn = $default ? '[Y/n]' : '[y/N]';
        while (1) {
        while (1) {
-               print $question,' ',($default ? '[Y/n]' : '[y/N]'), ' ';
+               print $question,' ',$yn, ' ';
+               if ($forceyes && $forceno) {
+                       print "$default (from config/command line)\n";
+                       return $default;
+               };
+               if ($forceyes) {
+                       print "YES (from config/command line)\n";
+                       return 1;
+               };
+               if ($forceno) {
+                       print "NO (from config/command line)\n";
+                       return 0;
+               };
+
                $answer = <STDIN>;
                $answer = <STDIN>;
+               if (!defined $answer) {
+                       $OUTPUT_AUTOFLUSH = 1;
+                       die "\n\n".
+                           "End of STDIN reached.  Are you using xargs?  Caff wants to read from STDIN,\n".
+                           "so you can't really use it with xargs.  A patch against caff to read from\n".
+                           "the terminal would be appreciated.\n".
+                           "For now instead of   cat keys | xargs caff  do  caff `cat keys`\n";
+               };
                chomp $answer;
                chomp $answer;
-               last if ((defined $answer) && (length $answer <= 1));
-               print "grrrrrr.\n";
+               last if ((length $answer == 0) || ($answer =~ m/^[yYnN]$/) );
+               print "What about $yn is so hard to understand?\nAnswer with either 'n' or 'y' or just press enter for the default.\n";
                sleep 1;
        };
        my $result = $default;
                sleep 1;
        };
        my $result = $default;
@@ -484,9 +582,16 @@ sub export_key($$) {
 
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
 
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
-       $gpg->options->hash_init(
-               'homedir' => $gnupghome,
-               'armor' => 1 );
+       if (defined $gnupghome) {
+               $gpg->options->hash_init(
+                       'homedir' => $gnupghome,
+                       'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always } ],
+                       'armor' => 1 );
+       } else {
+               $gpg->options->hash_init(
+                       'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always } ],
+                       'armor' => 1 );
+       };
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        my $pid = $gpg->export_keys(handles => $handles, command_args => [ $keyid ]);
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        my $pid = $gpg->export_keys(handles => $handles, command_args => [ $keyid ]);
@@ -504,7 +609,9 @@ sub import_key($$) {
 
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
 
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
-       $gpg->options->hash_init( 'homedir' => $gnupghome );
+       $gpg->options->hash_init(
+               'homedir' => $gnupghome,
+               'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always } ] );
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        my $pid = $gpg->import_keys(handles => $handles);
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        my $pid = $gpg->import_keys(handles => $handles);
@@ -552,9 +659,9 @@ sub send_mail($$$@) {
                        Type        => "application/pgp-keys",
                        Disposition => 'attachment',
                        Encoding    => "7bit",
                        Type        => "application/pgp-keys",
                        Disposition => 'attachment',
                        Encoding    => "7bit",
-                       Description => "PGP Key 0x$key_id, uid ".($key->{'text'}).' ('.($key->{'serial'}).')',
+                       Description => "PGP Key 0x$key_id, uid ".($key->{'text'}).' ('.($key->{'serial'}).'), signed by 0x'.$CONFIG{'keyid'}[0],
                        Data        => $key->{'key'},
                        Data        => $key->{'key'},
-                       Filename    => "0x$key_id.".$key->{'serial'}.".asc");
+                       Filename    => "0x$key_id.".$key->{'serial'}.".signed-by-0x".$CONFIG{'keyid'}[0].".asc");
        };
 
        if ($can_encrypt) {
        };
 
        if ($can_encrypt) {
@@ -563,7 +670,7 @@ sub send_mail($$$@) {
                my $gpg = GnuPG::Interface->new();
                $gpg->call( $CONFIG{'gpg'} );
                $gpg->options->hash_init( 'homedir' => $GNUPGHOME,
                my $gpg = GnuPG::Interface->new();
                $gpg->call( $CONFIG{'gpg'} );
                $gpg->options->hash_init( 'homedir' => $GNUPGHOME,
-                       'extra_args' => '--always-trust',
+                       'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always } ],
                        'armor' => 1 );
                $gpg->options->meta_interactive( 0 );
                my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
                        'armor' => 1 );
                $gpg->options->meta_interactive( 0 );
                my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
@@ -669,10 +776,10 @@ if (!GetOptions (
        '-V'              =>  \$params->{'version'},
        '-u=s'            =>  \$params->{'local-user'},
        '--local-user=s'  =>  \$params->{'local-user'},
        '-V'              =>  \$params->{'version'},
        '-u=s'            =>  \$params->{'local-user'},
        '--local-user=s'  =>  \$params->{'local-user'},
-       '-e'              =>  \$params->{'export'},
-       '--export'        =>  \$params->{'export'},
-       '-E'              =>  \$params->{'no-export'},
-       '--no-export'     =>  \$params->{'no-export'},
+       '-e'              =>  \$params->{'export-old'},
+       '--export-old'    =>  \$params->{'export-old'},
+       '-E'              =>  \$params->{'no-export-old'},
+       '--no-export-old' =>  \$params->{'no-export-old'},
        '-m'              =>  \$params->{'mail'},
        '--mail'          =>  \$params->{'mail'},
        '-M'              =>  \$params->{'no-mail'},
        '-m'              =>  \$params->{'mail'},
        '--mail'          =>  \$params->{'mail'},
        '-M'              =>  \$params->{'no-mail'},
@@ -681,6 +788,7 @@ if (!GetOptions (
        '--no-download'   =>  \$params->{'no-download'},
        '-S'              =>  \$params->{'no-sign'},
        '--no-sign'       =>  \$params->{'no-sign'},
        '--no-download'   =>  \$params->{'no-download'},
        '-S'              =>  \$params->{'no-sign'},
        '--no-sign'       =>  \$params->{'no-sign'},
+       '--key-file=s@'   =>  \$params->{'key-files'},
        )) {
        usage(\*STDERR, 1);
 };
        )) {
        usage(\*STDERR, 1);
 };
@@ -698,7 +806,7 @@ usage(\*STDERR, 1) unless scalar @ARGV >= 1;
 if ($params->{'local-user'}) {
        $USER = $params->{'local-user'};
        $USER =~ s/^0x//i;
 if ($params->{'local-user'}) {
        $USER = $params->{'local-user'};
        $USER =~ s/^0x//i;
-       unless ($USER =~ /^([A-Z0-9]{8}|[A-Z0-9]{16}|[A-Z0-9]{32}|[A-Z0-9]{40})$/i) {
+       unless ($USER =~ /^([A-F0-9]{8}|[A-F0-9]{16}|[A-F0-9]{40})$/i) {
                print STDERR "-u $USER is not a keyid.\n";
                usage(\*STDERR, 1);
        };
                print STDERR "-u $USER is not a keyid.\n";
                usage(\*STDERR, 1);
        };
@@ -707,7 +815,11 @@ if ($params->{'local-user'}) {
 
 for my $keyid (@ARGV) {
        $keyid =~ s/^0x//i;
 
 for my $keyid (@ARGV) {
        $keyid =~ s/^0x//i;
-       unless ($keyid =~ /^([A-Z0-9]{8}|[A-Z0-9]{16}|[A-Z0-9]{32}|[A-Z0-9]{40})$/i) {
+       unless ($keyid =~ /^([A-F0-9]{8}|[A-F0-9]{16}||[A-F0-9]{40})$/i) {
+               if ($keyid =~ /^[A-F0-9]{32}$/) {
+                       info("Ignoring v3 fingerprint $keyid.  v3 keys are obsolete.");
+                       next;
+               };
                print STDERR "$keyid is not a keyid.\n";
                usage(\*STDERR, 1);
        };
                print STDERR "$keyid is not a keyid.\n";
                usage(\*STDERR, 1);
        };
@@ -718,32 +830,59 @@ $CONFIG{'no-download'} = $params->{'no-download'} if defined $params->{'no-downl
 $CONFIG{'no-mail'}     = $params->{'no-mail'}     if defined $params->{'no-mail'};
 $CONFIG{'mail'}        = $params->{'mail'}        if defined $params->{'mail'};
 $CONFIG{'no-sign'}     = $params->{'no-sign'}     if defined $params->{'no-sign'};
 $CONFIG{'no-mail'}     = $params->{'no-mail'}     if defined $params->{'no-mail'};
 $CONFIG{'mail'}        = $params->{'mail'}        if defined $params->{'mail'};
 $CONFIG{'no-sign'}     = $params->{'no-sign'}     if defined $params->{'no-sign'};
+push @{$CONFIG{'key-files'}}, @{$params->{'key-files'}} if defined $params->{'key-files'};
 
 
 #################
 # import own keys
 #################
 
 
 #################
 # import own keys
 #################
+for my $keyid (@{$CONFIG{'keyid'}}) {
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
        $gpg->options->hash_init(
                'homedir' => $GNUPGHOME,
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
        $gpg->options->hash_init(
                'homedir' => $GNUPGHOME,
-               'extra_args' => '--keyserver='.$CONFIG{'keyserver'} );
+               'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always --with-colons --fixed-list-mode --fast-list-mode } ] );
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
-       $gpg->options->hash_init( 'extra_args' => [ '--with-colons', '--fixed-list-mode' ] );
-       my $pid = $gpg->list_public_keys(handles => $handles, command_args => $CONFIG{'keyid'});
+       my $pid = $gpg->list_public_keys(handles => $handles, command_args => $keyid);
        my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd);
        waitpid $pid, 0;
        my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd);
        waitpid $pid, 0;
+
        if ($stdout eq '') {
        if ($stdout eq '') {
-               warn ("No data from gpg for list-key\n");
-               next;
+               warn ("No data from gpg for list-key\n"); # There should be at least 'tru:' everywhere.
        };
        };
-       foreach my $keyid (@{$CONFIG{'keyid'}}) {
-               unless ($stdout =~ /^pub:(?:[^:]*:){3,3}$keyid:/m) {
-                       info("Importing $keyid");
-                       system "gpg --export $keyid | gpg --import --homedir $GNUPGHOME";
-               }
+       unless ($stdout =~ /^pub:(?:[^:]*:){3,3}$keyid:/m) {
+               info("Key $keyid not found in caff's home.  Getting it from your normal GnuPGHome.");
+               my $key = export_key(undef, $keyid);
+               if (!defined $key || $key eq '') {
+                       warn ("Did not get key $keyid from your normal GnuPGHome\n");
+                       next;
+               };
+               my $result = import_key($GNUPGHOME, $key);
+               unless ($result) {
+                       warn ("Could not import $keyid into caff's gnupghome.\n");
+                       next;
+               };
        }
        }
+}
+
+########################
+# import keys from files
+########################
+foreach my $keyfile (@{$CONFIG{'key-files'}}) {
+    my $gpg = GnuPG::Interface->new();
+    $gpg->call( $CONFIG{'gpg'} );
+    $gpg->options->hash_init('homedir' => $GNUPGHOME);
+    $gpg->options->meta_interactive( 0 );
+    my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
+    my $pid = $gpg->import_keys(handles => $handles, command_args => $keyfile);
+    my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd);
+    info ("Importing keys from $keyfile");
+    waitpid $pid, 0;
+    if ($status !~ /^\[GNUPG:\] IMPORT_OK/m) {
+       warn $stderr;
+    }
+}
 
 #############################
 # receive keys from keyserver
 
 #############################
 # receive keys from keyserver
@@ -753,15 +892,12 @@ if ($CONFIG{'no-download'}) {
        @keyids_ok = @KEYIDS;
 } else {
        info ("fetching keys, this will take a while...");
        @keyids_ok = @KEYIDS;
 } else {
        info ("fetching keys, this will take a while...");
-       if (grep { /^[A-Z0-9]{32}$/ } @KEYIDS) {
-               info ("found v3 key fingerprints in argument list - note that HKP keyservers do not support retrieving v3 keys by fingerprint");
-       }
 
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
        $gpg->options->hash_init(
                'homedir' => $GNUPGHOME,
 
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
        $gpg->options->hash_init(
                'homedir' => $GNUPGHOME,
-               'extra_args' => '--keyserver='.$CONFIG{'keyserver'} );
+               'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always }, '--keyserver='.$CONFIG{'keyserver'} ] );
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        my $pid = $gpg->recv_keys(handles => $handles, command_args => [ @KEYIDS ]);
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        my $pid = $gpg->recv_keys(handles => $handles, command_args => [ @KEYIDS ]);
@@ -774,21 +910,23 @@ if ($CONFIG{'no-download'}) {
 # [GNUPG:] IMPORT_OK 0 25FC1614B8F87B52FF2F99B962AF4031C82E0039
        my %local_keyids = map { $_ => 1 } @KEYIDS;
        for my $line (split /\n/, $status) {
 # [GNUPG:] IMPORT_OK 0 25FC1614B8F87B52FF2F99B962AF4031C82E0039
        my %local_keyids = map { $_ => 1 } @KEYIDS;
        for my $line (split /\n/, $status) {
-               if ($line =~ /^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{8})([0-9A-F]{16})([0-9A-F]{8})([0-9A-F]{0,8})/) {
-                       my $imported_key;
-                       $imported_key = $1.$2.$3    if $local_keyids{$1.$2.$3}; # v3 key
-                       $imported_key = $1.$2.$3.$4 if $local_keyids{$1.$2.$3.$4};
-                       $imported_key =       $3.$4 if $local_keyids{      $3.$4};
-                       $imported_key =          $4 if $local_keyids{         $4};
-                       unless ($imported_key) {
-                           warn("Imported unexpected key; got: $imported_key.\n");
+               if ($line =~ /^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{40})/) {
+                       my $imported_key = $1;
+                       my $whole_fpr = $imported_key;
+                       my $long_keyid = substr($imported_key, -16);
+                       my $short_keyid = substr($imported_key, -8);
+                       my $speced_key;
+                       for my $spec (($whole_fpr, $long_keyid, $short_keyid)) {
+                               $speced_key = $spec if $local_keyids{$spec};
+                       };
+                       unless ($speced_key) {
+                           notice ("Imported unexpected key; got: $imported_key\n");
                            next;
                        };
                            next;
                        };
-                       debug ("Imported $imported_key");
-                       delete $local_keyids{$imported_key};
+                       debug ("Imported $imported_key for $speced_key");
+                       delete $local_keyids{$speced_key};
                        unshift @keyids_ok, $imported_key;
                        unshift @keyids_ok, $imported_key;
-               } elsif ($line =~ /^\[GNUPG:\] NODATA 1$/) {
-               } elsif ($line =~ /^\[GNUPG:\] IMPORT_RES /) {
+               } elsif ($line =~ /^\[GNUPG:\] (NODATA|IMPORT_RES|IMPORTED) /) {
                } else {
                        notice ("got unknown reply from gpg: $line");
                }
                } else {
                        notice ("got unknown reply from gpg: $line");
                }
@@ -807,6 +945,10 @@ unless (@keyids_ok) {
 ###########
 # sign keys
 ###########
 ###########
 # sign keys
 ###########
+if ($CONFIG{'ask-sign'} && ! $CONFIG{'no-sign'}) {
+       $CONFIG{'no-sign'} = ! ask("Continue with signing?", 1);
+}
+       
 unless ($CONFIG{'no-sign'}) {
        info("Sign the following keys according to your policy, then exit gpg with 'save' after signing each key");
        for my $keyid (@keyids_ok) {
 unless ($CONFIG{'no-sign'}) {
        info("Sign the following keys according to your policy, then exit gpg with 'save' after signing each key");
        for my $keyid (@keyids_ok) {
@@ -815,10 +957,11 @@ unless ($CONFIG{'no-sign'}) {
                push @command, '--local-user', $USER if (defined $USER);
                push @command, "--homedir=$GNUPGHOME";
                push @command, '--secret-keyring', $CONFIG{'secret-keyring'};
                push @command, '--local-user', $USER if (defined $USER);
                push @command, "--homedir=$GNUPGHOME";
                push @command, '--secret-keyring', $CONFIG{'secret-keyring'};
-               push @command, split ' ', $CONFIG{'gpg-sign-args'} || "";
+               push @command, '--no-auto-check-trustdb';
+               push @command, '--trust-model=always';
                push @command, '--edit', $keyid;
                push @command, 'sign';
                push @command, '--edit', $keyid;
                push @command, 'sign';
-               push @command, 'save';
+               push @command, split ' ', $CONFIG{'gpg-sign-args'} || "";
                print join(' ', @command),"\n";
                system (@command);
        };
                print join(' ', @command),"\n";
                system (@command);
        };
@@ -833,10 +976,11 @@ for my $keyid (@keyids_ok) {
        #################
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
        #################
        my $gpg = GnuPG::Interface->new();
        $gpg->call( $CONFIG{'gpg'} );
-       $gpg->options->hash_init( 'homedir' => $GNUPGHOME );
+       $gpg->options->hash_init(
+               'homedir' => $GNUPGHOME,
+               'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always --with-colons --fixed-list-mode } ] );
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
        $gpg->options->meta_interactive( 0 );
        my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
-       $gpg->options->hash_init( 'extra_args' => [ '--with-colons', '--fixed-list-mode' ] );
        my $pid = $gpg->list_public_keys(handles => $handles, command_args => [ $keyid ]);
        my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd);
        waitpid $pid, 0;
        my $pid = $gpg->list_public_keys(handles => $handles, command_args => [ $keyid ]);
        my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd);
        waitpid $pid, 0;
@@ -894,7 +1038,7 @@ for my $keyid (@keyids_ok) {
                $gpg->call( $CONFIG{'gpg-delsig'} );
                $gpg->options->hash_init(
                        'homedir' => $tempdir,
                $gpg->call( $CONFIG{'gpg-delsig'} );
                $gpg->options->hash_init(
                        'homedir' => $tempdir,
-                       'extra_args' => [ '--with-colons', '--fixed-list-mode', '--command-fd=0', '--no-tty' ] );
+                       'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always --with-colons --fixed-list-mode --command-fd=0 --no-tty } ] );
                ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
                $pid = $gpg->wrap_call(
                        commands     => [ '--edit' ],
                ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds();
                $pid = $gpg->wrap_call(
                        commands     => [ '--edit' ],
@@ -999,7 +1143,7 @@ for my $keyid (@keyids_ok) {
 
                if ($signed_by_me) {
                        if ($NOW - $signed_by_me > $CONFIG{'export-sig-age'} ) {
 
                if ($signed_by_me) {
                        if ($NOW - $signed_by_me > $CONFIG{'export-sig-age'} ) {
-                               my $write = ask("Signature on $this_uid_text is old.  Export?", 0, $params->{export}, $params->{'no-export'});
+                               my $write = ask("Signature on $this_uid_text is old.  Export?", 0, $params->{'export-old'}, $params->{'no-export-old'});
                                next unless $write;
                        };
                        my $keydir = "$KEYSBASE/$DATE_STRING";
                                next unless $write;
                        };
                        my $keydir = "$KEYSBASE/$DATE_STRING";
@@ -1040,7 +1184,7 @@ for my $keyid (@keyids_ok) {
                        if (!$uid->{'is_uat'} && ($uid->{'text'} =~ /@/)) {
                                my $address = $uid->{'text'};
                                $address =~ s/.*<(.*)>.*/$1/;
                        if (!$uid->{'is_uat'} && ($uid->{'text'} =~ /@/)) {
                                my $address = $uid->{'text'};
                                $address =~ s/.*<(.*)>.*/$1/;
-                               if (ask("Send mail to '$address' for $uid->{'text'}?", 1, $CONFIG{'mail'})) {
+                               if (ask("Mail signature for $uid->{'text'} to '$address'?", 1, $CONFIG{'mail'})) {
                                        my $mail = send_mail($address, $can_encrypt, $longkeyid, $uid, @attached);
 
                                        my $keydir = "$KEYSBASE/$DATE_STRING";
                                        my $mail = send_mail($address, $can_encrypt, $longkeyid, $uid, @attached);
 
                                        my $keydir = "$KEYSBASE/$DATE_STRING";