Skip to content

Commit ed1bf54

Browse files
committed
gh-45154: Fix imaplib handling of READ-ONLY mailboxes
1 parent b87613f commit ed1bf54

3 files changed

Lines changed: 27 additions & 13 deletions

File tree

Lib/imaplib.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,15 @@ class IMAP4:
166166
167167
Errors raise the exception class <instance>.error("<reason>").
168168
IMAP4 server errors raise <instance>.abort("<reason>"),
169-
which is a sub-class of 'error'. Mailbox status changes
170-
from READ-WRITE to READ-ONLY raise the exception class
171-
<instance>.readonly("<reason>"), which is a sub-class of 'abort'.
169+
which is a sub-class of 'error'.
170+
171+
When the server returns a READ-ONLY response code, the is_readonly
172+
attribute is set to True. Applications should check this attribute
173+
to determine mailbox access level.
172174
173175
"error" exceptions imply a program error.
174176
"abort" exceptions imply the connection should be reset, and
175177
the command re-tried.
176-
"readonly" exceptions imply the command should be re-tried.
177178
178179
Note: to use this module, you must read the RFCs pertaining to the
179180
IMAP4 protocol, as the semantics of the arguments to each IMAP4
@@ -860,12 +861,8 @@ def select(self, mailbox='INBOX', readonly=False):
860861
self.state = 'AUTH' # Might have been 'SELECTED'
861862
return typ, dat
862863
self.state = 'SELECTED'
863-
if 'READ-ONLY' in self.untagged_responses \
864-
and not readonly:
865-
if __debug__:
866-
if self.debug >= 1:
867-
self._dump_ur(self.untagged_responses)
868-
raise self.readonly('%s is not writable' % mailbox)
864+
if 'READ-ONLY' in self.untagged_responses:
865+
self.is_readonly = True
869866
return typ, self.untagged_responses.get('EXISTS', [None])
870867

871868

@@ -1094,9 +1091,8 @@ def _command(self, name, *args):
10941091
if typ in self.untagged_responses:
10951092
del self.untagged_responses[typ]
10961093

1097-
if 'READ-ONLY' in self.untagged_responses \
1098-
and not self.is_readonly:
1099-
raise self.readonly('mailbox status changed to READ-ONLY')
1094+
if 'READ-ONLY' in self.untagged_responses:
1095+
self.is_readonly = True
11001096

11011097
tag = self._new_tag()
11021098
name = bytes(name, self._encoding)

Lib/test/test_imaplib.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,21 @@ def test_unselect(self):
657657
self.assertEqual(data[0], b'Returned to authenticated state. (Success)')
658658
self.assertEqual(client.state, 'AUTH')
659659

660+
def test_select_readonly_mailbox(self):
661+
class ReadOnlyHandler(SimpleIMAPHandler):
662+
def cmd_SELECT(self, tag, args):
663+
self.server.is_selected = True
664+
self._send_line(b'* 1 EXISTS')
665+
self._send_line(b'* OK [READ-ONLY] Mailbox is read-only')
666+
self._send_tagged(tag, 'OK', '[READ-ONLY] SELECT completed')
667+
client, _ = self._setup(ReadOnlyHandler)
668+
client.login('user', 'pass')
669+
self.assertFalse(client.is_readonly)
670+
typ, data = client.select('INBOX')
671+
self.assertEqual(typ, 'OK')
672+
self.assertTrue(client.is_readonly)
673+
self.assertEqual(client.state, 'SELECTED')
674+
660675
# property tests
661676

662677
def test_file_property_should_not_be_accessed(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :mod:`imaplib` to handle mailboxes with ACL rights like ``lrs`` correctly
2+
by setting ``is_readonly`` flag instead of raising exception. Patched by Shamil
3+
Abdulaev.

0 commit comments

Comments
 (0)