Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions Lib/imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,15 @@ class IMAP4:

Errors raise the exception class <instance>.error("<reason>").
IMAP4 server errors raise <instance>.abort("<reason>"),
which is a sub-class of 'error'. Mailbox status changes
from READ-WRITE to READ-ONLY raise the exception class
<instance>.readonly("<reason>"), which is a sub-class of 'abort'.
which is a sub-class of 'error'.

When the server returns a READ-ONLY response code, the is_readonly
attribute is set to True. Applications should check this attribute
to determine mailbox access level.

"error" exceptions imply a program error.
"abort" exceptions imply the connection should be reset, and
the command re-tried.
"readonly" exceptions imply the command should be re-tried.

Note: to use this module, you must read the RFCs pertaining to the
IMAP4 protocol, as the semantics of the arguments to each IMAP4
Expand Down Expand Up @@ -860,12 +861,8 @@ def select(self, mailbox='INBOX', readonly=False):
self.state = 'AUTH' # Might have been 'SELECTED'
return typ, dat
self.state = 'SELECTED'
if 'READ-ONLY' in self.untagged_responses \
and not readonly:
if __debug__:
if self.debug >= 1:
self._dump_ur(self.untagged_responses)
raise self.readonly('%s is not writable' % mailbox)
if 'READ-ONLY' in self.untagged_responses:
self.is_readonly = True
return typ, self.untagged_responses.get('EXISTS', [None])


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

if 'READ-ONLY' in self.untagged_responses \
and not self.is_readonly:
raise self.readonly('mailbox status changed to READ-ONLY')
if 'READ-ONLY' in self.untagged_responses:
self.is_readonly = True

tag = self._new_tag()
name = bytes(name, self._encoding)
Expand Down
15 changes: 15 additions & 0 deletions Lib/test/test_imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,21 @@ def test_unselect(self):
self.assertEqual(data[0], b'Returned to authenticated state. (Success)')
self.assertEqual(client.state, 'AUTH')

def test_select_readonly_mailbox(self):
class ReadOnlyHandler(SimpleIMAPHandler):
def cmd_SELECT(self, tag, args):
self.server.is_selected = True
self._send_line(b'* 1 EXISTS')
self._send_line(b'* OK [READ-ONLY] Mailbox is read-only')
self._send_tagged(tag, 'OK', '[READ-ONLY] SELECT completed')
client, _ = self._setup(ReadOnlyHandler)
client.login('user', 'pass')
self.assertFalse(client.is_readonly)
typ, data = client.select('INBOX')
self.assertEqual(typ, 'OK')
self.assertTrue(client.is_readonly)
self.assertEqual(client.state, 'SELECTED')

# property tests

def test_file_property_should_not_be_accessed(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :mod:`imaplib` to handle mailboxes with ACL rights like ``lrs`` correctly
by setting ``is_readonly`` flag instead of raising exception. Patched by Shamil
Abdulaev.
Loading