Changeset 91:cd7e6ad6d118
- Timestamp:
- 28/12/09 18:37:09 (2 years ago)
- Author:
- msmits@…
- Branch:
- default
- Message:
-
Backslash escaped double quotes in folder names now handled correctly
Also extracted the common code for list_folders and
list_sub_folders. The tests act on that directly.
- Location:
- imapclient
- Files:
-
Legend:
- Unmodified
- Added
- Removed
-
|
r90
|
r91
|
|
| 64 | 64 | |
| 65 | 65 | re_sep = re.compile('^\(\("[^"]*" "([^"]+)"\)\)') |
| 66 | | re_folder = re.compile('\([^)]*\) "[^"]+" "?([^"]+)"?') |
| | 66 | # re_folder = re.compile('\([^)]*\) "[^"]+" "?([^"]+)"?') |
| | 67 | re_folder = re.compile(r'\([^)]*\) "[^"]+" (?P<qqq>"?)(?P<folder>.+)(?P=qqq)') |
| 67 | 68 | re_status = re.compile(r'^\s*"?(?P<folder>[^"]+)"?\s+' |
| 68 | 69 | r'\((?P<status_items>.*)\)$') |
| … |
… |
|
| 160 | 161 | typ, data = self._imap.list(directory, pattern) |
| 161 | 162 | self._checkok('list', typ, data) |
| 162 | | |
| | 163 | return self._proc_folder_list(data) |
| | 164 | |
| | 165 | |
| | 166 | def list_sub_folders(self, directory="", pattern="*"): |
| | 167 | """Get a listing of subscribed folders on the server. |
| | 168 | |
| | 169 | The default behaviour (no args) will list all subscribed folders for the |
| | 170 | logged in user. |
| | 171 | |
| | 172 | @param directory: The base directory to look for folders from. |
| | 173 | @param pattern: A pattern to match against folder names. Only folder |
| | 174 | names matching this pattern will be returned. Wildcards accepted. |
| | 175 | @return: A list of folder names. As per the return of list_folders(). |
| | 176 | """ |
| | 177 | typ, data = self._imap.lsub(directory, pattern) |
| | 178 | self._checkok('lsub', typ, data) |
| | 179 | return self._proc_folder_list(data) |
| | 180 | |
| | 181 | |
| | 182 | def _proc_folder_list(self, folder_data): |
| 163 | 183 | folders = [] |
| 164 | | for line in data: |
| | 184 | for line in folder_data: |
| 165 | 185 | #TODO can the FetchParser code be adapted for use here? |
| 166 | 186 | folder_text = None |
| … |
… |
|
| 170 | 190 | match = self.re_folder.match(line) |
| 171 | 191 | if match: |
| 172 | | folder_text = match.group(1) |
| | 192 | folder_text = match.group('folder') |
| | 193 | folder_text = folder_text.replace(r'\"', '"') |
| 173 | 194 | if folder_text is not None: |
| 174 | 195 | folders.append(self._decode_folder_name(folder_text)) |
| 175 | 196 | return folders |
| 176 | | |
| 177 | | |
| 178 | | def list_sub_folders(self, directory="", pattern="*"): |
| 179 | | """Get a listing of subscribed folders on the server. |
| 180 | | |
| 181 | | The default behaviour (no args) will list all subscribed folders for the |
| 182 | | logged in user. |
| 183 | | |
| 184 | | @param directory: The base directory to look for folders from. |
| 185 | | @param pattern: A pattern to match against folder names. Only folder |
| 186 | | names matching this pattern will be returned. Wildcards accepted. |
| 187 | | @return: A list of folder names. As per the return of list_folders(). |
| 188 | | """ |
| 189 | | typ, data = self._imap.lsub(directory, pattern) |
| 190 | | self._checkok('lsub', typ, data) |
| 191 | | |
| 192 | | folders = [] |
| 193 | | for line in data: |
| 194 | | if line: |
| 195 | | m = self.re_folder.match(line) |
| 196 | | if m: |
| 197 | | folders.append(self._decode_folder_name(m.group(1))) |
| 198 | | return folders |
| 199 | | |
| | 197 | |
| 200 | 198 | |
| 201 | 199 | def select_folder(self, folder): |
-
|
r87
|
r91
|
|
| 6 | 6 | from imapclient.fixed_offset import FixedOffset |
| 7 | 7 | from imapclient.imapclient import datetime_to_imap |
| 8 | | from imapclient.test.mock import patch, sentinel |
| | 8 | from imapclient.test.mock import patch, sentinel, Mock |
| 9 | 9 | from imapclient.test.testable_imapclient import TestableIMAPClient as IMAPClient |
| 10 | 10 | import unittest |
| … |
… |
|
| 19 | 19 | class TestListFolders(IMAPClientTest): |
| 20 | 20 | |
| 21 | | def test_simple(self): |
| 22 | | self.client._imap.list.return_value = ('OK', ['(\\HasNoChildren) "/" "A"', |
| 23 | | '(\\HasNoChildren) "/" "Foo Bar"', |
| 24 | | ]) |
| | 21 | def test_list_folders(self): |
| | 22 | self.client._imap.list.return_value = ('OK', sentinel.folder_data) |
| | 23 | self.client._proc_folder_list = Mock(return_value=sentinel.folder_list) |
| 25 | 24 | |
| 26 | 25 | folders = self.client.list_folders(sentinel.dir, sentinel.pattern) |
| 27 | 26 | |
| 28 | 27 | self.assert_(self.client._imap.list.call_args == ((sentinel.dir, sentinel.pattern), {})) |
| 29 | | self.assert_(folders == ['A', 'Foo Bar']) |
| | 28 | self.assert_(self.client._proc_folder_list.call_args == ((sentinel.folder_data,), {})) |
| | 29 | self.assert_(folders is sentinel.folder_list) |
| | 30 | |
| | 31 | |
| | 32 | def test_list_sub_folders(self): |
| | 33 | self.client._imap.lsub.return_value = ('OK', sentinel.folder_data) |
| | 34 | self.client._proc_folder_list = Mock(return_value=sentinel.folder_list) |
| | 35 | |
| | 36 | folders = self.client.list_sub_folders(sentinel.dir, sentinel.pattern) |
| | 37 | |
| | 38 | self.assert_(self.client._imap.lsub.call_args == ((sentinel.dir, sentinel.pattern), {})) |
| | 39 | self.assert_(self.client._proc_folder_list.call_args == ((sentinel.folder_data,), {})) |
| | 40 | self.assert_(folders is sentinel.folder_list) |
| 30 | 41 | |
| 31 | 42 | |
| 32 | | def test_NO(self): |
| | 43 | def test_list_folders_NO(self): |
| 33 | 44 | self.client._imap.list.return_value = ('NO', ['badness']) |
| 34 | 45 | self.assertRaises(IMAPClient.Error, self.client.list_folders) |
| 35 | 46 | |
| 36 | 47 | |
| | 48 | def test_list_sub_folders_NO(self): |
| | 49 | self.client._imap.list.return_value = ('NO', ['badness']) |
| | 50 | self.assertRaises(IMAPClient.Error, self.client.list_folders) |
| | 51 | |
| | 52 | |
| | 53 | def test_simple(self): |
| | 54 | folders = self.client._proc_folder_list(['(\\HasNoChildren) "/" "A"', |
| | 55 | '(\\HasNoChildren) "/" "Foo Bar"', |
| | 56 | ]) |
| | 57 | self.assert_(folders == ['A', 'Foo Bar']) |
| | 58 | |
| | 59 | |
| | 60 | |
| | 61 | |
| 37 | 62 | def test_without_quotes(self): |
| 38 | | self.client._imap.list.return_value = ('OK', ['(\\HasNoChildren) "/" A', |
| 39 | | '(\\HasNoChildren) "/" B', |
| 40 | | '(\\HasNoChildren) "/" C', |
| 41 | | ]) |
| 42 | | |
| 43 | | folders = self.client.list_folders() |
| | 63 | folders = self.client._proc_folder_list(['(\\HasNoChildren) "/" A', |
| | 64 | '(\\HasNoChildren) "/" B', |
| | 65 | '(\\HasNoChildren) "/" C', |
| | 66 | ]) |
| 44 | 67 | self.assert_(folders == ['A', 'B', 'C'], 'got %r' % folders) |
| 45 | 68 | |
| 46 | 69 | |
| 47 | 70 | def test_mixed(self): |
| 48 | | self.client._imap.list.return_value = ('OK', ['(\\HasNoChildren) "/" Alpha', |
| 49 | | '(\\HasNoChildren) "/" "Foo Bar"', |
| 50 | | '(\\HasNoChildren) "/" C', |
| 51 | | ]) |
| 52 | | |
| 53 | | folders = self.client.list_folders() |
| | 71 | folders = self.client._proc_folder_list(['(\\HasNoChildren) "/" Alpha', |
| | 72 | '(\\HasNoChildren) "/" "Foo Bar"', |
| | 73 | '(\\HasNoChildren) "/" C', |
| | 74 | ]) |
| 54 | 75 | self.assert_(folders == ['Alpha', 'Foo Bar', 'C'], 'got %r' % folders) |
| 55 | 76 | |
| 56 | 77 | |
| 57 | 78 | def test_funky_characters(self): |
| 58 | | self.client._imap.list.return_value = ('OK', |
| 59 | | [('(\\NoInferiors \\UnMarked) "/" {5}', 'bang\xff'), |
| 60 | | '', |
| 61 | | '(\\HasNoChildren \\UnMarked) "/" "INBOX"']) |
| | 79 | folders = self.client._proc_folder_list([('(\\NoInferiors \\UnMarked) "/" {5}', 'bang\xff'), |
| | 80 | '', |
| | 81 | '(\\HasNoChildren \\UnMarked) "/" "INBOX"']) |
| | 82 | self.assert_(folders == ['bang\xff', 'INBOX'], 'got %r' % folders) |
| 62 | 83 | |
| 63 | | folders = self.client.list_folders() |
| 64 | | self.assert_(folders == ['bang\xff', 'INBOX'], 'got %r' % folders) |
| | 84 | |
| | 85 | def test_escaped_quotes(self): |
| | 86 | folders = self.client._proc_folder_list(['(\\HasNoChildren) "/" "Test \"Folder\""', |
| | 87 | '(\\HasNoChildren) "/" "Left\"Right"', |
| | 88 | ]) |
| | 89 | self.assert_(folders == ['Test "Folder"', 'Left\"Right'], 'got %r' % folders) |
| | 90 | |
| | 91 | |
| | 92 | def test_other_escaping(self): |
| | 93 | self.fail("what other escapes are allowed?") |
| 65 | 94 | |
| 66 | 95 | |