folder/IMAP, repository/IMAP: make encoding conditional on utf_8_support

When utf_8_support is False (the default, standard RFC 3501 mode),
folder names received from the server are in Modified UTF-7 and must
be kept in that encoding internally.  When utf_8_support is True,
names are decoded to UTF-8 for internal use.

Previous code decoded unconditionally in IMAPFolder.__init__, which
would corrupt non-ASCII names received as Modified UTF-7 when
utf_8_support is False.  The inverse problem existed in
getfullIMAPname() and the three encode_mailbox_name() call sites in
IMAPRepository: they always converted UTF-8 → Modified UTF-7 before
sending to the server, which is wrong when utf_8_support is False
(names are already in Modified UTF-7 and must not be double-encoded).

Fix by applying the same conditional pattern consistently:

  if account.utf_8_support:
      name = imaputil.utf8_IMAP(name)   # UTF-8 → Modified UTF-7
  return imaputil.foldername_to_imapname(name)

This is applied in:
  - IMAPFolder.__init__       (decode on receive)
  - IMAPFolder.getfullIMAPname (encode before SELECT)
  - IMAPRepository.getfolders  (folderincludes SELECT)
  - IMAPRepository.deletefolder
  - IMAPRepository.makefolder_single

encode_mailbox_name() (which always assumed UTF-8 input) is removed
as it is no longer used anywhere.

Based on patch by Etienne Buira <etienne.buira@free.fr>
This commit is contained in:
Rodolfo García Peñas (kix)
2026-05-17 11:22:35 +02:00
parent 56b8cbca01
commit 1f04bbd8bf
3 changed files with 15 additions and 9 deletions
+5 -2
View File
@@ -41,7 +41,7 @@ class IMAPFolder(BaseFolder):
# a folder object from a locally available utf_8 name)
# In any case the given name is first dequoted.
name = imaputil.dequote(name)
if decode:
if decode and repository.account.utf_8_support:
name = imaputil.IMAP_utf8(name)
self.sep = imapserver.delim
super(IMAPFolder, self).__init__(name, repository)
@@ -82,7 +82,10 @@ class IMAPFolder(BaseFolder):
imapobj.select(self.getfullIMAPname(), readonly=True, force=force)
def getfullIMAPname(self):
return imaputil.encode_mailbox_name(self.getfullname())
name = self.getfullname()
if self.repository.account.utf_8_support:
name = imaputil.utf8_IMAP(name)
return imaputil.foldername_to_imapname(name)
# Interface from BaseFolder
def suggeststhreads(self):
-4
View File
@@ -449,10 +449,6 @@ def utf7m_search_function(name):
codecs.register(utf7m_search_function)
def encode_mailbox_name(mbox_name):
return foldername_to_imapname(utf8_IMAP(mbox_name))
def foldername_to_imapname(folder_name):
"""
This function returns the folder_name ready to send to the
+10 -3
View File
@@ -752,7 +752,10 @@ class IMAPRepository(BaseRepository):
try:
for foldername in self.folderincludes:
try:
imapobj.select(imaputil.encode_mailbox_name(foldername),
imap_name = foldername
if self.account.utf_8_support:
imap_name = imaputil.utf8_IMAP(foldername)
imapobj.select(imaputil.foldername_to_imapname(imap_name),
readonly=True)
except OfflineImapError as exc:
# couldn't select this folderinclude, so ignore folder.
@@ -816,7 +819,9 @@ class IMAPRepository(BaseRepository):
def deletefolder(self, foldername):
"""Delete a folder on the IMAP server."""
foldername = imaputil.encode_mailbox_name(foldername)
if self.account.utf_8_support:
foldername = imaputil.utf8_IMAP(foldername)
foldername = imaputil.foldername_to_imapname(foldername)
imapobj = self.imapserver.acquireconnection()
try:
result = imapobj.delete(foldername)
@@ -877,7 +882,9 @@ class IMAPRepository(BaseRepository):
return
imapobj = self.imapserver.acquireconnection()
try:
foldername = imaputil.encode_mailbox_name(foldername)
if self.account.utf_8_support:
foldername = imaputil.utf8_IMAP(foldername)
foldername = imaputil.foldername_to_imapname(foldername)
result = imapobj.create(foldername)
if result[0] != 'OK':