diff --git a/pyquarantine/cli.py b/pyquarantine/cli.py index 79e7fc0..461d5f5 100644 --- a/pyquarantine/cli.py +++ b/pyquarantine/cli.py @@ -15,6 +15,7 @@ # import argparse +import json import logging import logging.handlers import sys @@ -92,7 +93,7 @@ def print_table(columns, rows): def list_quarantines(quarantines, args): if args.batch: - print("\n".join([q.name for q in quarantines])) + print("\n".join([q["name"] for q in quarantines])) else: qlist = [] for q in quarantines: @@ -280,8 +281,14 @@ def delete(quarantines, args): def get(quarantines, args): storage = _get_quarantine(quarantines, args.quarantine, args.debug).storage - _, msg = storage.get_mail(args.quarantine_id) - print(msg.as_string()) + data = storage.get_mail_bytes(args.quarantine_id) + sys.stdout.buffer.write(data) + + +def metadata(quarantines, args): + storage = _get_quarantine(quarantines, args.quarantine, args.debug).storage + metadata = storage.get_metadata(args.quarantine_id) + print(json.dumps(metadata)) class StdErrFilter(logging.Filter): @@ -462,6 +469,17 @@ def main(): metavar="ID", help="Quarantine ID.") quarantine_get_parser.set_defaults(func=get) + # quarantine metadata command + quarantine_metadata_parser = quarantine_subparsers.add_parser( + "metadata", + description="Get metadata of email from quarantine.", + help="Get metadata of email from quarantine", + formatter_class=formatter_class) + quarantine_metadata_parser.add_argument( + "quarantine_id", + metavar="ID", + help="Quarantine ID.") + quarantine_metadata_parser.set_defaults(func=metadata) # whitelist command group whitelist_parser = subparsers.add_parser( diff --git a/pyquarantine/storage.py b/pyquarantine/storage.py index 0dc0b17..c696513 100644 --- a/pyquarantine/storage.py +++ b/pyquarantine/storage.py @@ -24,7 +24,7 @@ import os from calendar import timegm from datetime import datetime -from email import message_from_binary_file +from email import message_from_bytes from email.policy import SMTPUTF8 from glob import glob from time import gmtime @@ -80,10 +80,10 @@ class FileMailStorage(BaseMailStorage): super().__init__(original, metadata, metavar, pretend) # check if directory exists and is writable if not os.path.isdir(directory) or \ - not os.access(directory, os.W_OK): + not os.access(directory, os.R_OK): raise RuntimeError( f"directory '{directory}' does not exist or is " - f"not writable") + f"not readable") self.directory = directory try: self.mode = int(mode, 8) if mode is not None else None @@ -346,18 +346,23 @@ class FileMailStorage(BaseMailStorage): else: self._save_metafile(metafile, metadata) + def get_mail_bytes(self, storage_id): + _, datafile = self._get_file_paths(storage_id) + try: + with open(datafile, "rb") as fh: + data = fh.read() + except IOError as e: + raise RuntimeError(f"unable to open email data file: {e}") + return data + def get_mail(self, storage_id): super().get_mail(storage_id) metadata = self.get_metadata(storage_id) - _, datafile = self._get_file_paths(storage_id) - try: - with open(datafile, "rb") as fh: - msg = message_from_binary_file( - fh, _class=MilterMessage, policy=SMTPUTF8.clone( - refold_source='none')) - except IOError as e: - raise RuntimeError(f"unable to open email data file: {e}") + msg = message_from_bytes( + self.get_mail_bytes(storage_id), + _class=MilterMessage, + policy=SMTPUTF8.clone(refold_source='none')) return (metadata, msg)