61 lines
1.6 KiB
Python
61 lines
1.6 KiB
Python
"""Codec para UTF-7 modificado (RFC 3501), usado por IMAP para nombres de carpetas."""
|
|
|
|
import base64
|
|
|
|
_B64_CHARS = "-,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+"
|
|
|
|
|
|
def encode(name: str) -> bytes:
|
|
"""Codifica un nombre de carpeta Unicode a UTF-7 modificado (IMAP)."""
|
|
res = []
|
|
buffer = []
|
|
|
|
def flush():
|
|
if not buffer:
|
|
return
|
|
raw = "".join(buffer).encode("utf-16-be")
|
|
b64 = base64.b64encode(raw).decode("ascii").rstrip("=")
|
|
b64 = b64.replace("/", ",")
|
|
res.append("&" + b64 + "-")
|
|
buffer.clear()
|
|
|
|
for ch in name:
|
|
code = ord(ch)
|
|
if ch == "&":
|
|
flush()
|
|
res.append("&-")
|
|
elif 0x20 <= code <= 0x7E:
|
|
flush()
|
|
res.append(ch)
|
|
else:
|
|
buffer.append(ch)
|
|
flush()
|
|
return "".join(res).encode("ascii")
|
|
|
|
|
|
def decode(data: bytes) -> str:
|
|
"""Decodifica un nombre de carpeta IMAP en UTF-7 modificado a texto Unicode."""
|
|
s = data.decode("ascii")
|
|
res = []
|
|
i = 0
|
|
n = len(s)
|
|
while i < n:
|
|
ch = s[i]
|
|
if ch == "&":
|
|
end = s.find("-", i + 1)
|
|
if end == -1:
|
|
end = n
|
|
segment = s[i + 1:end]
|
|
if segment == "":
|
|
res.append("&")
|
|
else:
|
|
segment = segment.replace(",", "/")
|
|
padding = "=" * (-len(segment) % 4)
|
|
raw = base64.b64decode(segment + padding)
|
|
res.append(raw.decode("utf-16-be"))
|
|
i = end + 1
|
|
else:
|
|
res.append(ch)
|
|
i += 1
|
|
return "".join(res)
|