From 36294f630e6c1e1e74617b3d45e30f6c3624d272 Mon Sep 17 00:00:00 2001 From: Alex Selimov Date: Tue, 22 Apr 2025 22:20:03 -0400 Subject: [PATCH] Completed initial version of maildir_clean --- src/maildirclean/cli.py | 45 +++++++++++++++++++++++++++++-------- src/maildirclean/filedir.py | 14 ++++++++++-- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/maildirclean/cli.py b/src/maildirclean/cli.py index e2c3792..4bb7a16 100644 --- a/src/maildirclean/cli.py +++ b/src/maildirclean/cli.py @@ -2,9 +2,23 @@ import argparse import sys from pathlib import Path +from maildirclean.filedir import delete_all_from_selected_email + from .maildir import MailDir, TopSender, parse_maildir +class InputError(Exception): + """Exception raised for custom error scenarios. + + Attributes: + message -- explanation of the error + """ + + def __init__(self): + self.message = "Please enter a valid number or 'q' to quit" + super().__init__(self.message) + + def parse_arguments() -> argparse.Namespace: """Parse command line arguments @@ -24,6 +38,15 @@ def parse_arguments() -> argparse.Namespace: default=5, help="Number of top senders to display (default: 5)", ) + + parser.add_argument( + "--no-confirm", + dest="confirm", + action="store_false", + default=True, + help="Skip confirmation prompts", + ) + parser.add_argument( "--verbose", "-v", action="store_true", help="Enable verbose output" ) @@ -78,14 +101,19 @@ def run_loop(args: argparse.Namespace, maildir_path: str | Path): ) print(output) - if not user_input_loop(top_senders, maildir): + if not user_input_loop(top_senders, maildir, args.confirm): break -def user_input_loop(top_senders: list[TopSender], maildir: MailDir) -> bool: +def user_input_loop(top_senders: list[TopSender], maildir: MailDir, confirm) -> bool: user_input = input("> ").strip() - while handle_user_input(user_input, top_senders, maildir): - user_input = input("> ").strip() + + while True: + try: + return handle_user_input(user_input, top_senders, maildir, confirm) + except InputError as ex: + print(ex.message) + user_input = input("> ").strip() def parse_selections(user_input, max_selection): @@ -146,15 +174,14 @@ def parse_selections(user_input, max_selection): return selections -def handle_user_input(user_input, top_senders, maildir): +def handle_user_input(user_input, top_senders, maildir, confirm) -> bool: if user_input.lower() == "q": return False try: selections = parse_selections(user_input, len(top_senders)) - for selection in selections: - selected_sender = top_senders[selection - 1] - print(f"Selected {selected_sender.email}") + selected_senders = [top_senders[selection - 1] for selection in selections] + delete_all_from_selected_email(selected_senders, maildir, confirm) return True except ValueError: - print("Please enter a valid number or 'q' to quit") + raise InputError diff --git a/src/maildirclean/filedir.py b/src/maildirclean/filedir.py index 9033db6..2f403d8 100644 --- a/src/maildirclean/filedir.py +++ b/src/maildirclean/filedir.py @@ -5,9 +5,19 @@ import os from maildirclean.maildir import MailDir, TopSender -def delete_all_from_selected_email(selected_senders: list[TopSender], maildir: MailDir): +def delete_all_from_selected_email( + selected_senders: list[TopSender], maildir: MailDir, confirm=True +): for sender in selected_senders: - delete_files(maildir.get_paths_for_email(sender.email)) + emails = maildir.get_paths_for_email(sender.email) + if confirm: + print( + f"Deleting {len(emails)} addressed from sender {sender.email}\nConfirm (y)" + ) + if input("> ").strip() not in ["y", "Y", "yes", "Yes"]: + print(f"Cancelling delete") + continue + delete_files(emails) maildir.remove_email(sender.email)