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 )