Allow entire FPRs on the command line
[pgp-tools.git] / caff / caff
index fe5fd9778d9e0dee3d99cc3485b07edf8486665b..4bbab0aedfab23c84aaf4dbc4ed0ea9d84e31e3d 100755 (executable)
--- a/caff/caff
+++ b/caff/caff
@@ -39,7 +39,7 @@ caff -- CA - Fire and Forget
 
 =over
 
-=item B<caff> [-u I<yourkeyid>] I<keyid> [I<keyid> ..]
+=item B<caff> [-mMR] [-u I<yourkeyid>] I<keyid> [I<keyid> ..]
 
 =back
 
@@ -55,6 +55,14 @@ sigs and sigs done by you.
 
 =over
 
+=item B<-m> B<-M>
+
+Send/do not send mail after signing. Default is to ask the user for each uid.
+
+=item B<-R>
+
+Do not retrieve the key to be signed from a keyserver.
+
 =item B<-u> I<yourkeyid>
 
 Select the key that is used for signing, in case you have more than one key.
@@ -121,9 +129,9 @@ B<gpg> is set to.
 
 =item B<gpg-delsig> [string]
 
-Path to the GnuPG binary which is used to split off signatures.  This is
-needed while the upstream GnuPG is not fixed  (there are 2 bugs in the
-Debian Bug Tracking System).  Default: what B<gpg> is set to.
+Path to the GnuPG binary which is used to split off signatures.  This was
+needed while the upstream GnuPG was not fixed.  Default: what B<gpg>
+is set to.
 
 =item B<secret-keyring> [string]
 
@@ -162,6 +170,7 @@ use File::Temp qw{tempdir};
 use MIME::Entity;
 use Fcntl;
 use IO::Select;
+use Getopt::Std;
 use GnuPG::Interface;
 
 my %CONFIG;
@@ -231,7 +240,7 @@ sub readwrite_gpg($$$$$%) {
 
        trace("Entering readwrite_gpg.");
 
-       my ($first_line, $dummy) = split /\n/, $in;
+       my ($first_line, undef) = split /\n/, $in;
        debug("readwrite_gpg sends ".(defined $first_line ? $first_line : "<nothing>"));
 
        local $INPUT_RECORD_SEPARATOR = undef;
@@ -368,7 +377,7 @@ my $DATE_STRING = sprintf("%04d-%02d-%02d", $year+1900, $mon+1, $mday);
 
 sub usage() {
        print STDERR "caff $VERSION - (c) 2004, 2005 Peter Palfrader\n";
-       print STDERR "Usage: $PROGRAM_NAME [-u <yourkeyid>] <keyid> [<keyid> ...]\n";
+       print STDERR "Usage: $PROGRAM_NAME [-mMR] [-u <yourkeyid>] <keyid> [<keyid> ...]\n";
        exit 1;
 };
 
@@ -485,12 +494,13 @@ sub sanitize_uid($) {
 
 my $USER;
 my @KEYIDS;
+my %opt;
+
+getopts('mMRu:', \%opt);
 
 usage() unless scalar @ARGV >= 1;
-if ($ARGV[0] eq '-u') {
-       usage() unless scalar @ARGV >= 3;
-       shift @ARGV;
-       $USER = shift @ARGV;
+if ($opt{u}) {
+       $USER = $opt{u};
        $USER =~ s/^0x//i;
        unless ($USER =~ /^[A-Za-z0-9]{8,8}([A-Za-z0-9]{8})?$/) {
                print STDERR "-u $USER is not a keyid.\n";
@@ -500,7 +510,7 @@ if ($ARGV[0] eq '-u') {
 };
 for my $keyid (@ARGV) {
        $keyid =~ s/^0x//i;
-       unless ($keyid =~ /^[A-Za-z0-9]{8}([A-Za-z0-9]{8})?$/) {
+       unless ($keyid =~ /^[A-Za-z0-9]{8}([A-Za-z0-9]{8}|[A-Za-z0-9]{32})?$/) {
                print STDERR "$keyid is not a keyid.\n";
                usage();
        };
@@ -539,7 +549,7 @@ for my $keyid (@ARGV) {
 #############################
 my @keyids_ok;
 my @keyids_failed;
-if ($CONFIG{'no-download'}) {
+if ($CONFIG{'no-download'} or $opt{R}) {
        @keyids_ok = @KEYIDS;
 } else {
        my $gpg = GnuPG::Interface->new();
@@ -563,19 +573,29 @@ if ($CONFIG{'no-download'}) {
 # [GNUPG:] IMPORT_OK 0 25FC1614B8F87B52FF2F99B962AF4031C82E0039
                my $handled = 0;
                for my $line (split /\n/, $status) {
-                       if ($line =~ /^\[GNUPG:\] IMPORT_OK/) {
-                               push @keyids_ok, shift @KEYIDS;
+                       if ($line =~ /^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{40})/) {
+                               my $imported_key = $1;
+                               if ($keyid ne $imported_key &&
+                                   $keyid ne substr($imported_key, -16) &&
+                                   $keyid ne substr($imported_key, -8)) {
+                                   warn("Imported unexpected key.  expected: $keyid; got: $imported_key.\n");
+                                   next;
+                               };
+                               push @keyids_ok, $keyid;
+                               shift @KEYIDS;
                                $handled = 1;
                                last;
                        } elsif ($line =~ /^\[GNUPG:\] NODATA/) {
-                               push @keyids_failed, shift @KEYIDS;
+                               push @keyids_failed, $keyid;
+                               shift @KEYIDS;
                                $handled = 1;
                                last;
                        };
                };
                unless ($handled) {
                        notice ("Huh, what's up with $keyid?");
-                       push @keyids_failed, shift @KEYIDS;
+                       push @keyids_failed, $keyid;
+                       shift @KEYIDS;
                };
        };
        die ("Still keys in \@KEYIDS.  This should not happen.") if scalar @KEYIDS;
@@ -620,14 +640,21 @@ for my $keyid (@keyids_ok) {
                warn ("No data from gpg for list-key $keyid\n");
                next;
        };
-       my $keyinfo = $stdout;
        my @publine = grep { /^pub/ } (split /\n/, $stdout);
-       my ($dummy1, $dummy2, $dummy3, $dummy4, $longkeyid, $dummy6, $dummy7, $dummy8, $dummy9, $dummy10, $dummy11, $flags) = split /:/, pop @publine;
-       my $can_encrypt = $flags =~ /E/;
+       my (undef, undef, undef, undef, $longkeyid, undef, undef, undef, undef, undef, undef, $flags) = split /:/, pop @publine;
+       if (scalar @publine > 0) {
+               warn ("More than one key matched $keyid.  Try to specify the long keyid or fingerprint\n");
+               next;
+       };
        unless (defined $longkeyid) {
-               warn ("Didn't find public keyid in edit dialog of key $keyid.\n");
+               warn ("Didn't find public keyid in --list-key of key $keyid.\n");
+               next;
+       };
+       unless (defined $flags) {
+               warn ("Didn't find flags in --list-key of key $keyid.\n");
                next;
        };
+       my $can_encrypt = $flags =~ /E/;
 
        # export the key
        ################
@@ -687,7 +714,7 @@ for my $keyid (@keyids_ok) {
                debug("Parsing stdout output.");
                for my $line (split /\n/, $stdout) {
                        debug("Checking line $line");
-                       my ($type, $dummy2, $dummy3, $dummy4, $dummy5, $dummy6, $dummy7, $dummy8, $dummy9, $uidtext) = split /:/, $line;
+                       my ($type, undef, undef, undef, undef, undef, undef, undef, undef, $uidtext) = split /:/, $line;
                        if ($type eq 'sub') {
                                $number_of_subkeys++;
                        };
@@ -747,7 +774,7 @@ for my $keyid (@keyids_ok) {
                        my $answer = "no";
                        if (defined $line) { # only if we found a sig here - we never remove revocation packets for instance
                                debug("[sigremoval] doing line $line.");
-                               my ($dummy1, $dummy2, $dummy3, $dummy4, $signer, $created, $dummy7, $dummy8, $dummy9) = split /:/, $line;
+                               my (undef, undef, undef, undef, $signer, $created, undef, undef, undef) = split /:/, $line;
                                if ($signer eq $longkeyid) {
                                        debug("[sigremoval] selfsig ($signer).");
                                        $answer = "no";
@@ -768,9 +795,9 @@ for my $keyid (@keyids_ok) {
                readwrite_gpg("save\n", $inputfd, $stdoutfd, $stderrfd, $statusfd);
                waitpid $pid, 0;
 
-               my $asciikey = export_key($tempdir, $longkeyid);
+               my $asciikey = export_key($tempdir, $keyid);
                if ($asciikey eq '') {
-                       warn ("No data from gpg for export $longkeyid\n");
+                       warn ("No data from gpg for export $keyid\n");
                        next;
                };
 
@@ -798,7 +825,9 @@ for my $keyid (@keyids_ok) {
        if (scalar @UIDS == 0) {
                info("found no signed uids for $keyid");
        } else {
-               my @attached ;
+               next if $opt{M}; # do not send mail
+
+               my @attached;
                for my $uid (@UIDS) {
                        trace("UID: $uid->{'text'}\n");
                        unless ($uid->{'text'} =~ /@/) {
@@ -812,8 +841,7 @@ for my $keyid (@keyids_ok) {
                        if ($uid->{'text'} =~ /@/) {
                                my $address = $uid->{'text'};
                                $address =~ s/.*<(.*)>.*/$1/;
-                               my $send = ask("Send mail to '$address' for $uid->{'text'}?", 1);
-                               if ($send) {
+                               if ($opt{m} or ask("Send mail to '$address' for $uid->{'text'}?", 1)) {
                                        my $mail = send_mail($address, $can_encrypt, $longkeyid, $uid, @attached);
 
                                        my $keydir = "$KEYSBASE/$DATE_STRING";