Skip to content

Commit

Permalink
Merge pull request #263 from mlorant/feat-unselect-200
Browse files Browse the repository at this point in the history
#200 - Add UNSELECT command
  • Loading branch information
mjs committed Aug 15, 2017
2 parents 46d56b2 + 2bf02ec commit 33a3aa3
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/src/releases.rst
Expand Up @@ -23,6 +23,7 @@ Added
- Search now supports nested criteria so that more complex criteria
can be expressed. IMAPClient will add parentheses in the right place.
- PLAIN authentication support (via `plain_login` method)
- `unselect_folder()` method, for servers with the UNSELECT capability (#200)

Changed
-------
Expand Down
17 changes: 17 additions & 0 deletions imapclient/imapclient.py
Expand Up @@ -53,6 +53,10 @@
if 'ID' not in imaplib.Commands:
imaplib.Commands['ID'] = ('NONAUTH', 'AUTH', 'SELECTED')

# ... and UNSELECT. RFC3691 does not specify the state but there is no
# reason to use the command without AUTH state and a mailbox selected.
if 'UNSELECT' not in imaplib.Commands:
imaplib.Commands['UNSELECT'] = ('AUTH', 'SELECTED')

# System flags
DELETED = br'\Deleted'
Expand Down Expand Up @@ -472,6 +476,19 @@ def select_folder(self, folder, readonly=False):
self._command_and_check('select', self._normalise_folder(folder), readonly)
return self._process_select_response(self._imap.untagged_responses)

def unselect_folder(self):
"""Unselect the current folder and release associated resources.
Unlike ``close_folder``, the ``UNSELECT`` command does not expunge
the mailbox, keeping messages with \Deleted flag set for example.
Returns the UNSELECT response string returned by the server.
"""
logger.debug('< UNSELECT')
# IMAP4 class has no `unselect` method so we can't use `_command_and_check` there
_typ, data = self._imap._simple_command("UNSELECT")
return data[0]

def _process_select_response(self, resp):
untagged = _dict_bytes_normaliser(resp)
out = {}
Expand Down
16 changes: 16 additions & 0 deletions imapclient/livetest.py
Expand Up @@ -234,6 +234,22 @@ def assertNoneOrTuple(val):
self.assertEqual(ns.other, ns[1])
self.assertEqual(ns.shared, ns[2])

def test_unselect_folder(self):
if not self.client.has_capability('UNSELECT'):
return self.skipTest("Server doesn't support UNSELECT")

resp = self.client.select_folder(self.base_folder)
self.assertEqual(resp[b'EXISTS'], 0)
self.client.search(['ALL'])
self.client.unselect_folder()

# To ensure the folder has been selected, check we can't run .search()
with self.assertRaises(IMAPClient.Error):
self.client.search(['ALL'])
# It should not be possible to unselect a folder if none have been selected yet
with self.assertRaises(IMAPClient.Error):
self.client.unselect_folder()

def test_select_and_close(self):
resp = self.client.select_folder(self.base_folder)
self.assertEqual(resp[b'EXISTS'], 0)
Expand Down
9 changes: 9 additions & 0 deletions imapclient/test/test_imapclient.py
Expand Up @@ -185,6 +185,15 @@ def test_normal(self):
b'OTHER': [b'blah']
})

def test_unselect(self):
self.client._imap._simple_command.return_value = ('OK', ['Unselect completed.'])
#self.client._imap._untagged_response.return_value = (
# b'OK', [b'("name" "GImap" "vendor" "Google, Inc.")'])

result = self.client.unselect_folder()
self.assertEqual(result, 'Unselect completed.')
self.client._imap._simple_command.assert_called_with('UNSELECT')


class TestAppend(IMAPClientTest):

Expand Down

0 comments on commit 33a3aa3

Please sign in to comment.