"""Shared IMAP mailbox-name helpers.""" import base64 import re def to_mutf7(s: str) -> str: """Encode a mailbox name as IMAP modified UTF-7.""" res = [] buf = [] for c in s: if 0x20 <= ord(c) <= 0x7E and c != "&": if buf: b64 = ( base64.b64encode("".join(buf).encode("utf-16-be")) .decode("ascii") .rstrip("=") .replace("/", ",") ) res.append(f"&{b64}-") buf.clear() res.append(c) elif c == "&": if buf: b64 = ( base64.b64encode("".join(buf).encode("utf-16-be")) .decode("ascii") .rstrip("=") .replace("/", ",") ) res.append(f"&{b64}-") buf.clear() res.append("&-") else: buf.append(c) if buf: b64 = ( base64.b64encode("".join(buf).encode("utf-16-be")) .decode("ascii") .rstrip("=") .replace("/", ",") ) res.append(f"&{b64}-") return "".join(res) def from_mutf7(s: str) -> str: """Decode an IMAP modified UTF-7 mailbox name.""" res = [] i = 0 while i < len(s): if s[i] == "&": j = s.index("-", i + 1) if j == i + 1: res.append("&") else: encoded = s[i + 1 : j].replace(",", "/") pad = (4 - len(encoded) % 4) % 4 res.append( base64.b64decode(encoded + "=" * pad).decode("utf-16-be") ) i = j + 1 else: res.append(s[i]) i += 1 return "".join(res) def quote_mailbox(folder: str) -> str: """Return an IMAP-safe quoted mailbox name.""" escaped = to_mutf7(folder).replace("\\", "\\\\").replace('"', r"\"") return f'"{escaped}"' def parse_folder_name(raw: bytes) -> str | None: """Extract and decode the mailbox name from an IMAP LIST response.""" decoded = raw.decode("ascii", errors="replace") match = re.match(r'\(.*?\)\s+".*?"\s+(.*)', decoded) if not match: return None name = match.group(1).strip().strip('"') if not name: return None try: return from_mutf7(name) except Exception: return name def list_folders(mail) -> list[str]: """Return decoded folder names from an IMAP connection.""" status, raw_folders = mail.list() if status != "OK" or not raw_folders: return [] folders = [parse_folder_name(item) for item in raw_folders if item] return sorted(folder for folder in folders if folder)