#!/usr/bin/perl -w
# 
# reads output of pgpk -ll (Version 5.0) and shows which public keys are 
# not signed by the other public keys. It takes only the primary userID's!
# Tested with pgp for linux Version 5.0 Beta 8
#
# Sample:
# ./pgpk -K sig50_filtered -ll >in
# ./analyse_pgp_sigs.pl <in >out
# 
# Written by Patrick Feisthammel, pafei@rubin.ch 
# May be freely used. 
#

%signed= {};  # $signed{'A'}= ('B', 'C') <=> A signed key of B and C 
@id= ();
&read_all_keys;
&chk_sigs;

sub chk_sigs {
    @id= sort(@id);
    foreach $chkid (@id) {
	print "checking sigs done by $chkid\n";
	my @sigarr= sort(@{$signed{$chkid}});
	my $i_id= 0;
	my $i_sig= 0;
	while (($i_id <= $#id) && ($i_sig <= $#sigarr)) {
	   # print "  i_sig= $i_sig   i_id= $i_id\n";
	    while (($sigarr[$i_sig] gt $id[$i_id]) && ($i_id <= $#id)) {
		print "  did not sign " . $id[$i_id] . "\n";
		$i_id++;
	    };
	    if ($sigarr[$i_sig] eq $id[$i_id]) {
		print "  signed $id[$i_id]\n";
		$i_sig++; $i_id++;
	    } else {
		print "#################### ?????\n";
		print "sigarr[i_sig]: $sigarr[$i_sig]\n";
		print "id[i_id]:      $id[$i_id]\n"; 
		print "  i_sig= $i_sig   i_id= $i_id\n";
	    };
	};
	while ($i_id <= $#id) {
	    print "  did not sign " . $id[$i_id] . "\n";
	    $i_id++;
	};
    };
}

sub read_all_keys {
    while (! eof(STDIN)) {
	($pub_id, @sig_id)= &read_one_key; 
	if (defined $pub_id) {
	    # print "------------ uid: $pub_id\n";
	    push @id, $pub_id;
	    foreach $sig (@sig_id) {
		if (! defined $signed{$sig}) {
		    @{$signed{$sig}}= ();
		};
		if (grep(/$pub_id/, @{$signed{$sig}}) > 0) {
		    print STDERR "Skipping double sig on $pub_id from $sig\n";
		} else {
		    push @{$signed{$sig}}, $pub_id;
		};
		# print "$sig signed " . ${@{$signed{$sig}}}[$#{@{$signed{$sig}}}] . "\n";
	    };
	};
    };
};
 

sub read_one_key {
# In:  -
# Out: ($pub_id, @sig_id);
# 
# reads from STDIN one pgp key with signatures (ending with an empty line and
# skipping everything before a line starting with 'pub'.

    my ($line, $tmp, $keyid);
    my @sig_id= ();

    my $skipping= 1;
    my $finished= eof(STDIN);
    # ----- skipping lines which do not start with 'uid' and remembering
    #   keyID from lines starting with 'pub'
    while ($skipping && (! $finished)) {
	$line= <STDIN>;
	chomp($line);
	while ($line=~ s/  / /) {};
	$finished= ($line =~ /^\s*$/) || eof(STDIN);
	$skipping= ($line !~ /^uid/);
	if ($line =~ /^pub/) {
	    ($tmp, $tmp, $keyid, $tmp)= split (/ /, $line, 4);
	}
	if ($skipping && ($line !~ /^pub/)) {
	    print STDERR "Skipping line $line\n";
	};
    };
    my ($pub_uid);
    if (! $finished) {
	($tmp, $pub_uid)= split(/ /, $line, 2); 
	$pub_uid= $keyid . ' ' . $pub_uid;
    };
    my($uid);
    my $sec_uid_found= 0;
    while (! $finished) {
	$line= <STDIN>;
	chomp($line);
	while ($line=~ s/  / /) {};
	$finished= ($line =~ /^\s*$/);
	if (! $sec_uid_found) {
	    if ($line =~ /^sig/) {
		($tmp, $keyid, $tmp, $uid)= split(/ /, $line, 4); 
		$uid= $keyid . ' ' . $uid;
		push @sig_id, $uid;
	    } else { 
		if ($line =~/^uid/) {
		    $sec_uid_found= 1;
		} else {
		    print STDERR "Skipping line $line\n";
		}
	    };
	} else {
	    print STDERR "Skipping sigs of second uid: $line\n";
	};
    };
    return ($pub_uid, @sig_id);
};




