Initial status for developed files on dagda
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user