App-Eduard

 view release on metacpan or  search on metacpan

lib/App/Eduard.pm  view on Meta::CPAN

}

sub first_part{
	my ($ent) = @_;
	return first_part ($ent->parts(0)) if $ent->parts;
	stringify [$ent->bodyhandle->as_lines]
}

sub import_pubkeys {
	my ($ent, $mg) = @_;
	my @keys;
	if ($ent->mime_type eq 'application/pgp-keys') {
		$ent = mp(1)->parse_data($ent->stringify);
		my $gpg = GnuPG::Interface->new;
		$mg->_set_options($gpg);
		$gpg->options->quiet(1);
		my ($input, $status) = (IO::Handle->new, IO::Handle->new);
		my $pid = $gpg->import_keys(handles => GnuPG::Handles->new(stdin => $input, status => $status));
		my $read = Mail::GnuPG::_communicate([$status], [$input], {$input => $ent->bodyhandle->as_string});
		push @keys, map { /IMPORT_OK \d+ (\w+)/ } $read->{$status};
		waitpid $pid, 0
	}
	push @keys, import_pubkeys ($_, $mg) for $ent->parts;
	@keys
}

sub find_pgp_part {
	my ($ent, $mg) = @_;
	do {
		my $part = find_pgp_part ($_, $mg);
		return $part if $part
	} for $ent->parts;
	return $ent if $ent->bodyhandle && ($mg->is_signed($ent) || $mg->is_encrypted($ent));
	return
}

sub process_message {
	my ($in) = @_;
	my $msg;
	my $parser = mp;

	$msg =                      $in   if     ref $in eq 'MIME::Entity';
	$msg = $parser->parse      ($in)  if     ref $in eq 'IO';
	$msg = $parser->parse_data ($in)  if     ref $in eq 'SCALAR';
	$msg = $parser->parse_open ($in)  unless ref $in;
	die "Don't know how to parse $in" unless $msg;

	if ($msg->mime_type ne 'multipart/signed' && $msg->mime_type ne 'multipart/encrypted') {
		# PGP/Inline requires decoding
		$parser->decode_bodies(1);
		$msg = $parser->parse_data($msg->stringify)
	}

	my $gpg = mg;
	if ($msg->effective_type ne 'multipart/signed' && $msg->effective_type ne 'multipart/encrypted' && !$msg->bodyhandle) {
		debug 'This is (probably) a PGP/Inline mail with attachments. Working around...';
		$msg = find_pgp_part $msg, $gpg
	}

	if ($gpg->is_signed($msg)) {
		debug 'This mail looks signed';
		my ($code, $keyid, $email) = $gpg->verify($msg);
		return sign_error => (
			message => stringify $gpg->{last_message}) if $code;
		return sign => (
			keyid   => $keyid,
			email   => $email,
			message => stringify $gpg->{last_message});
	}

	if ($gpg->is_encrypted($msg)) {
		debug 'This mail looks encrypted';
		my ($code, $keyid, $email) = $gpg->decrypt($msg);
		return encrypt_error => (
			message   => stringify $gpg->{last_message}) if $code;
		return encrypt => (
			plaintext => stringify $gpg->{plaintext},
			decrypted => $gpg->{decrypted},
			message   => stringify $gpg->{last_message}) unless defined $keyid;
		return signencrypt => (
			keyid     => $keyid,
			email     => $email,
			plaintext => stringify $gpg->{plaintext},
			decrypted => $gpg->{decrypted},
			message   => stringify $gpg->{last_message});
	}

	debug 'This mail doesn\'t seem to be signed or encrypted';
	return 'plain', message => ''
}

sub run {
	GetOptions(
		'always-trust!' => \$ENV{EDUARD_ALWAYS_TRUST},
		'debug!'        => \$ENV{EDUARD_DEBUG},
		'from=s'        => \$ENV{EDUARD_FROM},
		'key=s'         => \$ENV{EDUARD_KEY},
		'keydir=s'      => \$ENV{EDUARD_KEYDIR},
		'logfile=s'     => \$ENV{EDUARD_LOGFILE},
		'passphrase=s'  => \$ENV{EDUARD_PASSPHRASE},
		'tmpl-path=s'   => \$ENV{EDUARD_TMPL_PATH},
		'use-agent!'    => \$ENV{EDUARD_USE_AGENT},
	);
	my $tmpl_path = $ENV{EDUARD_TMPL_PATH} // 'en';
	open STDERR, '>>', $ENV{EDUARD_LOGFILE} if $ENV{EDUARD_LOGFILE};

	my $in = mp->parse(\*STDIN);
	debug 'Received mail from ', $in->get('From');
	my @keys = import_pubkeys $in, mg;
	say 'Found keys: ', join ' ', @keys if @keys;

	my ($tmpl, %params);
	try {
		($tmpl, %params) = process_message $in
	} catch {
		($tmpl, %params) = (error => message => $_)
	};
	debug "Result is $tmpl, GnuPG said:\n", $params{message};

	$params{plaintext} = first_part $params{decrypted} if $params{decrypted};

	my $tt = Template->new(INCLUDE_PATH => rel2abs $tmpl_path, dist_file 'App-Eduard', 'tmpl');
	my ($keys, $result) = ('', '');
	$tt->process('keys', {keys => \@keys}, \$keys) if @keys;
	$tt->process($tmpl, \%params, \$result);
	my $email = MIME::Entity->build(
		From    => $ENV{EDUARD_FROM},
		To      => $in->get('From'),
		Type    => 'text/plain; charset=UTF-8',
		Encoding=> '-SUGGEST',
		Subject => 'Re: ' . $in->get('Subject'),
		Data    => $keys.$result);



( run in 1.837 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )