=head1 NAME

dkim_sigh: attach a DKIM or DomainKeys signature to incoming mail before it is queued.
Currently we sign all authenticated and allowed relay email.

written by Shad L. Lords

=cut

require Mail::DKIM::Signer;
require Mail::DKIM::DkSignature;

sub register {
  my ($self, $qp, @args) = @_;
  %{$self->{_dkim}} = @args;
}

sub hook_data_post {
	my $self = shift;
	my $trns = shift;

	return DECLINED unless $self->qp->connection->relay_client() || ( $self->qp->auth_mechanism() && $self->qp->auth_user() );

	my $sender = (Qpsmtpd::Address->parse($trns->sender))[0];
	return DECLINED unless $sender;

	my $dkim = new Mail::DKIM::Signer( 
			Policy => sub {
					my $dkim = shift;

					my $headers = $self->{_dkim}->{dkim_headers} || "received:from:subject:date:message-id";
					$headers = $dkim->headers if $headers eq 'all';

					my $keys = $self->{_dkim}->{keys} || 'both';

					$dkim->add_signature(new Mail::DKIM::DkSignature(
							Algorithm => $self->{_dkim}->{algorithm} || "rsa-sha1",
							Method =>  $self->{_dkim}->{dk_method} || "nofws",
							Selector => $self->{_dkim}->{selector} || "default",
							Domain => $dkim->message_sender->host,
							Headers =>  $headers,
						)) if $keys eq 'both' || $keys eq 'dk' || $keys eq 'domainkeys';

					$dkim->add_signature(new Mail::DKIM::Signature(
							Algorithm => $self->{_dkim}->{algorithm} || "rsa-sha1",
							Method =>  $self->{_dkim}->{dkim_method} || "relaxed",
							Selector => $self->{_dkim}->{selector} || "default",
							Domain => $dkim->message_sender->host,
							Headers =>  $headers,
						)) if $keys eq 'both' || $keys eq 'dkim';

					return 1;
				},
			KeyFile => "config/dkimkeys/".$sender->host.".private"
		);
	return DECLINED unless $dkim;

	$trns->body_resetpos;
	foreach my $line (split /\n/, $trns->header->as_string) {
		chomp $line;
		$dkim->PRINT("$line\015\012");
	}
	while (my $line = $trns->body_getline) {
		chomp $line;
		$dkim->PRINT("$line\015\012");
	}
	$dkim->CLOSE;

	foreach my $sig ($dkim->signatures) {
		if ( (my $sig_string = $sig->as_string) =~ /^([^:]+):\s*(.*)$/) {
			$self->log(LOGINFO, "Added $1 for domain ".$sender->host);
			$trns->header->add("$1:", $2, 0);
		}
	}

	return DECLINED;
}
