Replace manual folder listing with list_selectable_folders utility
Easily exclude \NoSelect folders and folders whose status is not OK.
This commit is contained in:
parent
927fff17c7
commit
ed52587077
@ -306,14 +306,10 @@ def build_labels_manifest(imap_conn, local_path):
|
||||
|
||||
safe_print("--- Building Gmail Labels Manifest ---")
|
||||
|
||||
# Get all folders
|
||||
try:
|
||||
typ, folders = imap_conn.list()
|
||||
if typ != "OK":
|
||||
safe_print("Error: Could not list folders for label mapping.")
|
||||
return manifest
|
||||
except Exception as e:
|
||||
safe_print(f"Error listing folders: {e}")
|
||||
# Get all selectable folders and filter to label folders
|
||||
all_folders = imap_common.list_selectable_folders(imap_conn)
|
||||
if not all_folders:
|
||||
safe_print("Error: Could not list folders for label mapping.")
|
||||
return manifest
|
||||
|
||||
# First, scan [Gmail]/All Mail to get the authoritative flags for all emails
|
||||
@ -349,11 +345,7 @@ def build_labels_manifest(imap_conn, local_path):
|
||||
pass
|
||||
|
||||
# Parse folder names and filter to label folders
|
||||
label_folders = []
|
||||
for f_info in folders:
|
||||
name = imap_common.normalize_folder_name(f_info)
|
||||
if is_gmail_label_folder(name):
|
||||
label_folders.append(name)
|
||||
label_folders = [f for f in all_folders if is_gmail_label_folder(f)]
|
||||
|
||||
total_folders = len(label_folders)
|
||||
safe_print(f"Found {total_folders} label folders to scan.\n")
|
||||
@ -806,11 +798,9 @@ def main():
|
||||
elif args.folder:
|
||||
backup_folder(src, args.folder, local_path, src_conf, args.dest_delete)
|
||||
else:
|
||||
typ, folders = src.list()
|
||||
if typ == "OK":
|
||||
for f_info in folders:
|
||||
name = imap_common.normalize_folder_name(f_info)
|
||||
backup_folder(src, name, local_path, src_conf, args.dest_delete)
|
||||
folders = imap_common.list_selectable_folders(src)
|
||||
for name in folders:
|
||||
backup_folder(src, name, local_path, src_conf, args.dest_delete)
|
||||
|
||||
src.logout()
|
||||
print("\nBackup completed successfully.")
|
||||
|
||||
@ -114,8 +114,8 @@ def main():
|
||||
|
||||
# List Source Folders
|
||||
print("Listing folders in Source...")
|
||||
typ, folders = src.list()
|
||||
if typ != "OK":
|
||||
folders = imap_common.list_selectable_folders(src)
|
||||
if not folders:
|
||||
print("Failed to list source folders.")
|
||||
return
|
||||
|
||||
@ -129,8 +129,7 @@ def main():
|
||||
total_dest = 0
|
||||
|
||||
# Iterate through Source folders
|
||||
for folder_info in folders:
|
||||
folder_name = imap_common.normalize_folder_name(folder_info)
|
||||
for folder_name in folders:
|
||||
|
||||
# Get Counts
|
||||
src_count = get_email_count(src, folder_name)
|
||||
|
||||
@ -36,9 +36,9 @@ def count_emails(imap_server, username, password):
|
||||
|
||||
# List all mailboxes
|
||||
print("Listing mailboxes...")
|
||||
status, folders = mail.list()
|
||||
folders = imap_common.list_selectable_folders(mail)
|
||||
|
||||
if status != "OK":
|
||||
if not folders:
|
||||
print("Failed to list mailboxes.")
|
||||
return
|
||||
|
||||
@ -46,8 +46,7 @@ def count_emails(imap_server, username, password):
|
||||
print(f"{'Folder Name':<40} {'Count':>10}")
|
||||
print("-" * 52)
|
||||
|
||||
for folder_info in folders:
|
||||
folder_name = imap_common.normalize_folder_name(folder_info)
|
||||
for folder_name in folders:
|
||||
display_name = folder_name
|
||||
|
||||
try:
|
||||
|
||||
@ -64,6 +64,27 @@ def normalize_folder_name(folder_info_str):
|
||||
return folder_info_str.split()[-1].strip('"')
|
||||
|
||||
|
||||
def list_selectable_folders(imap_conn):
|
||||
"""
|
||||
Lists all selectable folders (excluding \\Noselect) on the IMAP connection.
|
||||
Returns a list of normalized folder name strings, or an empty list on failure.
|
||||
"""
|
||||
try:
|
||||
status, folders = imap_conn.list()
|
||||
if status != "OK" or not folders:
|
||||
return []
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
result = []
|
||||
for f in folders:
|
||||
f_str = f.decode("utf-8", errors="ignore") if isinstance(f, bytes) else str(f)
|
||||
if "\\Noselect" in f_str:
|
||||
continue
|
||||
result.append(normalize_folder_name(f))
|
||||
return result
|
||||
|
||||
|
||||
def decode_mime_header(header_value):
|
||||
"""
|
||||
Decodes MIME encoded headers (Subject, etc.) to a unicode (str) string.
|
||||
|
||||
@ -564,20 +564,17 @@ def main():
|
||||
)
|
||||
else:
|
||||
# Migration for all folders
|
||||
typ, folders = src_main.list()
|
||||
if typ == "OK":
|
||||
for folder_info in folders:
|
||||
name = imap_common.normalize_folder_name(folder_info)
|
||||
folders = imap_common.list_selectable_folders(src_main)
|
||||
for name in folders:
|
||||
# Auto-skip trash folder if we are utilizing it as a dump target
|
||||
# This prevents re-migrating the emails we just moved to trash
|
||||
if DELETE_SOURCE and trash_folder and name == trash_folder:
|
||||
safe_print(f"Skipping migration of Trash folder '{name}' (preventing circular migration).")
|
||||
continue
|
||||
|
||||
# Auto-skip trash folder if we are utilizing it as a dump target
|
||||
# This prevents re-migrating the emails we just moved to trash
|
||||
if DELETE_SOURCE and trash_folder and name == trash_folder:
|
||||
safe_print(f"Skipping migration of Trash folder '{name}' (preventing circular migration).")
|
||||
continue
|
||||
|
||||
migrate_folder(
|
||||
src_main, dest_main, name, DELETE_SOURCE, src_conf, dest_conf, trash_folder, DEST_DELETE
|
||||
)
|
||||
migrate_folder(
|
||||
src_main, dest_main, name, DELETE_SOURCE, src_conf, dest_conf, trash_folder, DEST_DELETE
|
||||
)
|
||||
|
||||
src_main.logout()
|
||||
dest_main.logout()
|
||||
|
||||
@ -145,7 +145,7 @@ class TestEmailCountingErrors:
|
||||
count_imap_emails.count_emails("host", "user", "pass")
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert "IMAP Error: Crash listing" in captured.out
|
||||
assert "Failed to list mailboxes" in captured.out
|
||||
|
||||
def test_imap_exception_during_select(self, monkeypatch, capsys):
|
||||
"""Test handling of IMAP4 exception during folder selection."""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user