summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/control2
-rwxr-xr-xemail-print-mime-structure22
-rw-r--r--email-print-mime-structure.1.pod24
3 files changed, 42 insertions, 6 deletions
diff --git a/debian/control b/debian/control
index fc2bccc..4c3b956 100644
--- a/debian/control
+++ b/debian/control
@@ -38,6 +38,8 @@ Depends:
Recommends:
devscripts,
git,
+ gpg,
+ gpg-agent,
notmuch,
python3-pgpy,
Architecture: all
diff --git a/email-print-mime-structure b/email-print-mime-structure
index c22d556..5497597 100755
--- a/email-print-mime-structure
+++ b/email-print-mime-structure
@@ -29,9 +29,11 @@ Example:
If you want to number the parts, i suggest piping the output through
something like "cat -n"
'''
+import os
import sys
import email
import logging
+import subprocess
from argparse import ArgumentParser, Namespace
from typing import Optional, Union, List, Tuple, Any
@@ -70,7 +72,7 @@ class MimePrinter(object):
nbytes = len(payload)
print(f'{prefix}{z.get_content_type()}{cset}{disposition}{fname} {nbytes:d} bytes')
- try_decrypt:bool = True if self.args.pgpkey else False
+ try_decrypt:bool = self.args.pgpkey or self.args.use_gpg_agent
if try_decrypt and \
(parent is not None) and \
@@ -84,6 +86,8 @@ class MimePrinter(object):
return
if self.args.pgpkey:
cryptopayload = self.pgpy_decrypt(self.args.pgpkey, ciphertext)
+ if cryptopayload is None and self.args.use_gpg_agent:
+ cryptopayload = self.gpg_decrypt(ciphertext)
if cryptopayload is None:
logging.warning(f'Unable to decrypt')
return
@@ -108,6 +112,19 @@ class MimePrinter(object):
pass
return None
+ def gpg_decrypt(self, ciphertext:str) -> Optional[Message]:
+ inp:int
+ outp:int
+ inp, outp = os.pipe()
+ with open(outp, 'w') as outf:
+ outf.write(ciphertext)
+ out:subprocess.CompletedProcess[bytes] = subprocess.run(['gpg', '--batch', '--decrypt'],
+ stdin=inp,
+ capture_output=True)
+ if out.returncode == 0:
+ return email.message_from_bytes(out.stdout)
+ return None
+
def print_tree(self, z:Message, prefix:str, parent:Optional[Message], num:int) -> None:
if (z.is_multipart()):
self.print_part(z, prefix+'┬╴', parent, num)
@@ -132,6 +149,9 @@ def main() -> None:
epilog="Example: email-print-mime-structure <message.eml")
parser.add_argument('--pgpkey', metavar='KEYFILE', action='append',
help='OpenPGP Transferable Secret Key for decrypting')
+ parser.add_argument('--use-gpg-agent', metavar='true|false', type=bool,
+ default=False,
+ help='Ask local GnuPG installation for decryption')
args:Namespace = parser.parse_args()
msg:Union[Message, str, int, Any] = email.message_from_file(sys.stdin)
diff --git a/email-print-mime-structure.1.pod b/email-print-mime-structure.1.pod
index b846d87..69b1cdc 100644
--- a/email-print-mime-structure.1.pod
+++ b/email-print-mime-structure.1.pod
@@ -29,6 +29,25 @@ standard input, this key will be tried for decryption. May be used
multiple times if you want to try decrypting with more than one secret
key.
+OpenPGP secret keys listed in B<--pgpkey=> are used ephemerally, and
+do not interact with any local GnuPG keyring.
+
+=item B<--use-gpg-agent=>I<true>|I<false>
+
+If I<true>, and B<email-print-mime-structure> encounters a
+PGP/MIME-encrypted part, it will try to decrypt the part using the
+secret keys found in the local installation of GnuPG. (default:
+I<false>)
+
+If both B<--pgpkey=>I<KEYFILE> and B<--use-gpg-agent=true> are
+supplied, I<KEYFILE> arguments will be tried before falling back to
+GnuPG.
+
+If B<email-print-mime-structure> has been asked to decrypt parts with
+either B<--pgpkey=>I<KEYFILE> or with B<--use-gpg-agent=true>, and it
+is unable to decrypt an encrypted part, it will emit a warning to
+stderr.
+
=item B<--help>, B<-h>
Show usage instructions.
@@ -49,11 +68,6 @@ Show usage instructions.
=head1 LIMITATIONS
-B<email-print-mime-structure> only decrypts encrypted e-mails using
-raw, non-password-protected OpenPGP secret keys (see B<--pgpkey>,
-above). If it is unable to decrypt an encrypted part with the
-supplied keys, it will warn on stderr.
-
B<email-print-mime-structure>'s output is not stable, and is not
intended to be interpreted by machines, so please do not depend on it
in scripts!