package PGP::Packet::Signature;

use strict;
use vars qw(@ISA %subpacket);

@ISA = qw(PGP::Packet);

use Carp;
use PGP::Unpackable;
use Digest::MD5;
use Digest::SHA1;

BEGIN {
    no strict 'refs';

# v3 fields:
# version sigtype created issuer
# pkalg hashalg
# hashbegin hashlen hashmsb16

# v4 fields:
# version sigtype subpacket:created subpacket:issuer
# pkalg hashalg
# hashbegin hashlen hashmsb16
# hashsubs unhashsubs

    foreach my $accessor (qw(version sigtype created issuer
			     pkalg hashalg
			     hashbegin hashlen hashmsb16
			     hashsubs unhashsubs)) {
	*{$accessor} = sub {
	    my ($this) = @_;
	    $this->{"parsed"} || $this->_parse();
	    $this->{$accessor};
	};
    }
}

sub new {
    my ($classname, $bodyref, $packetref) = @_;

    bless $classname->SUPER::new(2, $bodyref, $packetref), $classname;
}

sub _subpackets {
    my ($self, $subpackets) = @_;

    my $sps = {};

    while ($subpackets->remaining()) {
	my $plen;

	my $lbyte = $subpackets->unpackC();

	if ($lbyte < 192) {
	    $plen = $lbyte;
	} elsif ($lbyte < 224) {
	    my $octet = $subpackets->unpackC();
	    $plen = (($lbyte - 192) << 8) + $octet + 192;
	} elsif ($lbyte == 255) {
	    $plen = $subpackets->unpack("N");
	} else {
	    confess("partial body lengths are not permitted in subpackets");
	}

	my $type = $subpackets->unpackC();
	my $data = $subpackets->unpacka($plen-1);

	unshift(@{$sps->{$type}}, $data);
    }

    return($sps);
}

sub _parse {
    my ($self) = @_;
    my $body = new PGP::Unpackable($self->{"bodyref"});

    $self->{"hashbegin"} = $body->offset;
    my $version = $body->unpackC();
    $self->{"version"} = $version;
    if (($version == 2) || ($version == 3)) {
	# parse out stuff

	if ($body->unpackC() != 5) {
	    confess("hash material length != 5");
	}

	# clobber the above hashbegin
	$self->{"hashbegin"} = $body->offset;
	$self->{"sigtype"} = $body->unpackC();
	$self->{"created"} = $body->unpack("N");
	$self->{"hashlen"} = $body->offset - $self->{"hashbegin"};
	$self->{"issuer"} = $body->unpacka(8);
	$self->{"pkalg"} = $body->unpackC();
	$self->{"hashalg"} = $body->unpackC();
	$self->{"hashmsb16"} = $body->unpacka(2);

	# the parser can ignore the rest
    } elsif ($version == 4) {
	# parse out stuff

	$self->{"sigtype"} = $body->unpackC();
	$self->{"pkalg"} = $body->unpackC();
	$self->{"hashalg"} = $body->unpackC();

	my $hashsubslen = $body->unpack("n");
	my $hashsubs = new PGP::Unpackable(\$body->unpacka($hashsubslen));
	$self->{"hashsubs"} = $self->_subpackets($hashsubs);

	$self->{"hashlen"} = $body->offset - $self->{"hashbegin"};

	$self->{"unhashsubsbegin"} = $body->offset;

	my $unhashsubslen = $body->unpack("n");
	my $unhashsubs = new PGP::Unpackable(\$body->unpacka($unhashsubslen));
	$self->{"unhashsubs"} = $self->_subpackets($unhashsubs);

	$self->{"hashmsb16"} = $body->unpacka(2);
    } else {
	confess("unknown signature version $version");
    }

    $self->{"parsed"} = 1;
}

1;
