fix(mail): quote IMAP mailbox commands
This commit is contained in:
@@ -685,7 +685,7 @@ def _parse_fetch_parts_with_sequence(data: list[Any] | tuple[Any, ...] | None) -
|
|||||||
|
|
||||||
|
|
||||||
def _select_readonly(client: imaplib.IMAP4, folder: str) -> tuple[int, str | None]:
|
def _select_readonly(client: imaplib.IMAP4, folder: str) -> tuple[int, str | None]:
|
||||||
typ, data = client.select(folder, readonly=True)
|
typ, data = client.select(_quote_mailbox_name(folder), readonly=True)
|
||||||
if typ != "OK":
|
if typ != "OK":
|
||||||
raise ImapAppendError(f"IMAP folder {folder!r} could not be opened read-only: {data!r}", temporary=False)
|
raise ImapAppendError(f"IMAP folder {folder!r} could not be opened read-only: {data!r}", temporary=False)
|
||||||
selected_count = _decode_item(data[0] if data else None).strip()
|
selected_count = _decode_item(data[0] if data else None).strip()
|
||||||
@@ -1017,7 +1017,7 @@ def append_message_to_sent(
|
|||||||
client = _open_imap(imap_config)
|
client = _open_imap(imap_config)
|
||||||
target_folder = _effective_sent_folder(config=imap_config, requested_folder=folder, client=client)
|
target_folder = _effective_sent_folder(config=imap_config, requested_folder=folder, client=client)
|
||||||
internal_date = imaplib.Time2Internaldate(time.time())
|
internal_date = imaplib.Time2Internaldate(time.time())
|
||||||
typ, data = client.append(target_folder, "\\Seen", internal_date, message_bytes)
|
typ, data = client.append(_quote_mailbox_name(target_folder), "\\Seen", internal_date, message_bytes)
|
||||||
if typ != "OK":
|
if typ != "OK":
|
||||||
raise ImapAppendError(f"IMAP APPEND failed for folder {target_folder!r}: {data!r}", temporary=False)
|
raise ImapAppendError(f"IMAP APPEND failed for folder {target_folder!r}: {data!r}", temporary=False)
|
||||||
response = "; ".join(_decode_item(item) for item in (data or [])) or None
|
response = "; ".join(_decode_item(item) for item in (data or [])) or None
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from govoplan_mail.backend.config import ImapConfig
|
||||||
from govoplan_mail.backend.sending.imap import (
|
from govoplan_mail.backend.sending.imap import (
|
||||||
_detect_sent_folder,
|
_detect_sent_folder,
|
||||||
_extract_mailbox_name,
|
_extract_mailbox_name,
|
||||||
_normalize_mailbox_page,
|
_normalize_mailbox_page,
|
||||||
_paged_descending_sequences,
|
_paged_descending_sequences,
|
||||||
_parse_fetch_sequence,
|
_parse_fetch_sequence,
|
||||||
|
_select_readonly,
|
||||||
_sequence_set,
|
_sequence_set,
|
||||||
|
append_message_to_sent,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -69,5 +73,47 @@ class ImapMessagePaginationTests(unittest.TestCase):
|
|||||||
self.assertEqual(_normalize_mailbox_page(folder=" Sent ", limit=500, offset=3), ("Sent", 100, 3))
|
self.assertEqual(_normalize_mailbox_page(folder=" Sent ", limit=500, offset=3), ("Sent", 100, 3))
|
||||||
|
|
||||||
|
|
||||||
|
class ImapMailboxCommandTests(unittest.TestCase):
|
||||||
|
def test_select_quotes_mailbox_name_with_spaces(self):
|
||||||
|
class Client:
|
||||||
|
untagged_responses = {"EXISTS": [b"0"], "UIDVALIDITY": [b"1"]}
|
||||||
|
|
||||||
|
def select(self, mailbox, readonly=False):
|
||||||
|
self.mailbox = mailbox
|
||||||
|
self.readonly = readonly
|
||||||
|
return "OK", [b"0"]
|
||||||
|
|
||||||
|
def response(self, code):
|
||||||
|
return "OK", [b"1"] if code == "UIDVALIDITY" else []
|
||||||
|
|
||||||
|
client = Client()
|
||||||
|
|
||||||
|
self.assertEqual(_select_readonly(client, "Gesendete Elemente"), (0, "1"))
|
||||||
|
self.assertEqual(client.mailbox, '"Gesendete Elemente"')
|
||||||
|
self.assertTrue(client.readonly)
|
||||||
|
|
||||||
|
def test_append_quotes_mailbox_name_with_spaces(self):
|
||||||
|
class Client:
|
||||||
|
def append(self, mailbox, flags, date_time, message):
|
||||||
|
self.mailbox = mailbox
|
||||||
|
self.flags = flags
|
||||||
|
self.date_time = date_time
|
||||||
|
self.message = message
|
||||||
|
return "OK", [b"APPEND completed"]
|
||||||
|
|
||||||
|
def logout(self):
|
||||||
|
return "BYE", [b"logged out"]
|
||||||
|
|
||||||
|
client = Client()
|
||||||
|
config = ImapConfig(host="imap.example.org", username="user", password="secret", sent_folder="auto")
|
||||||
|
|
||||||
|
with patch("govoplan_mail.backend.sending.imap._open_imap", return_value=client):
|
||||||
|
result = append_message_to_sent(b"Subject: test\r\n\r\nBody", imap_config=config, folder="Gesendete Elemente")
|
||||||
|
|
||||||
|
self.assertEqual(client.mailbox, '"Gesendete Elemente"')
|
||||||
|
self.assertEqual(result.folder, "Gesendete Elemente")
|
||||||
|
self.assertEqual(result.bytes_appended, len(b"Subject: test\r\n\r\nBody"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user