IMAPClient 4.1.0__tar.gz → 4.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {imapclient-4.1.0 → imapclient-4.2.0/IMAPClient.egg-info}/PKG-INFO +2 -1
- {imapclient-4.1.0/IMAPClient.egg-info → imapclient-4.2.0}/PKG-INFO +2 -1
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/imapclient.py +41 -7
- {imapclient-4.1.0 → imapclient-4.2.0}/pyproject.toml +3 -1
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_imapclient.py +81 -6
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_init.py +13 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_util_functions.py +5 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/AUTHORS.rst +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/COPYING +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/IMAPClient.egg-info/SOURCES.txt +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/IMAPClient.egg-info/dependency_links.txt +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/IMAPClient.egg-info/entry_points.txt +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/IMAPClient.egg-info/top_level.txt +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/README.rst +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/__init__.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/config.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/datetime_util.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/exceptions.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/fixed_offset.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/imap4.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/imap_utf7.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/interact.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/livetest.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/response_lexer.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/response_parser.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/response_types.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/testable_imapclient.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/tls.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/typing_imapclient.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/util.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/imapclient/version.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/setup.cfg +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_auth.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_datetime_util.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_enable.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_fixed_offset.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_folder_status.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_imap_utf7.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_response_lexer.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_response_parser.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_search.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_sort.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_starttls.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_starttls_integration.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_store.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_thread.py +0 -0
- {imapclient-4.1.0 → imapclient-4.2.0}/tests/test_tls_integration.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IMAPClient
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Easy-to-use, Pythonic and complete IMAP client library
|
|
5
5
|
Author-email: Menno Finlay-Smits <hello@menno.io>
|
|
6
6
|
Maintainer-email: IMAPClient Maintainers <imapclient@groups.io>
|
|
7
|
+
License: BSD-3-Clause
|
|
7
8
|
Project-URL: Homepage, https://github.com/mjs/imapclient/
|
|
8
9
|
Keywords: imap,client,email,mail
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IMAPClient
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Easy-to-use, Pythonic and complete IMAP client library
|
|
5
5
|
Author-email: Menno Finlay-Smits <hello@menno.io>
|
|
6
6
|
Maintainer-email: IMAPClient Maintainers <imapclient@groups.io>
|
|
7
|
+
License: BSD-3-Clause
|
|
7
8
|
Project-URL: Homepage, https://github.com/mjs/imapclient/
|
|
8
9
|
Keywords: imap,client,email,mail
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -42,6 +42,7 @@ __all__ = [
|
|
|
42
42
|
"FLAGGED",
|
|
43
43
|
"DRAFT",
|
|
44
44
|
"RECENT",
|
|
45
|
+
"literal",
|
|
45
46
|
]
|
|
46
47
|
|
|
47
48
|
|
|
@@ -321,6 +322,21 @@ class IMAPClient:
|
|
|
321
322
|
|
|
322
323
|
connect_timeout = getattr(self._timeout, "connect", None)
|
|
323
324
|
|
|
325
|
+
if sys.version_info < (3, 9):
|
|
326
|
+
# Support for Python 3.8
|
|
327
|
+
if connect_timeout:
|
|
328
|
+
raise ValueError(
|
|
329
|
+
"connection timeout is not supported with this version of Python"
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
if self.ssl:
|
|
333
|
+
return tls.IMAP4_TLS(
|
|
334
|
+
self.host,
|
|
335
|
+
self.port,
|
|
336
|
+
self.ssl_context,
|
|
337
|
+
)
|
|
338
|
+
return imap4.IMAP4WithTimeout(self.host, self.port)
|
|
339
|
+
|
|
324
340
|
if self.ssl:
|
|
325
341
|
return tls.IMAP4_TLS(
|
|
326
342
|
self.host,
|
|
@@ -328,7 +344,6 @@ class IMAPClient:
|
|
|
328
344
|
self.ssl_context,
|
|
329
345
|
connect_timeout,
|
|
330
346
|
)
|
|
331
|
-
|
|
332
347
|
return imap4.IMAP4WithTimeout(self.host, self.port, connect_timeout)
|
|
333
348
|
|
|
334
349
|
def _set_read_timeout(self):
|
|
@@ -1461,9 +1476,9 @@ class IMAPClient:
|
|
|
1461
1476
|
yield to_bytes(seq_to_parenstr(m["flags"]))
|
|
1462
1477
|
if "date" in m:
|
|
1463
1478
|
yield to_bytes('"%s"' % datetime_to_INTERNALDATE(m["date"]))
|
|
1464
|
-
yield
|
|
1479
|
+
yield literal(to_bytes(m["msg"]))
|
|
1465
1480
|
else:
|
|
1466
|
-
yield
|
|
1481
|
+
yield literal(to_bytes(m))
|
|
1467
1482
|
|
|
1468
1483
|
msgs = list(chunks())
|
|
1469
1484
|
|
|
@@ -1709,11 +1724,25 @@ class IMAPClient:
|
|
|
1709
1724
|
prefix.append(b"UID")
|
|
1710
1725
|
prefix.append(command)
|
|
1711
1726
|
|
|
1712
|
-
|
|
1713
|
-
|
|
1727
|
+
# Check every argument before anything goes on the wire: a bad
|
|
1728
|
+
# argument found after a literal was sent would leave the server
|
|
1729
|
+
# waiting inside a half-sent command.
|
|
1730
|
+
for item in itertools.chain(prefix, args):
|
|
1714
1731
|
if not isinstance(item, bytes):
|
|
1715
1732
|
raise ValueError("command args must be passed as bytes")
|
|
1733
|
+
if b"\x00" in item:
|
|
1734
|
+
raise ValueError("NUL is not allowed in command arguments")
|
|
1735
|
+
if not _is8bit(item) and (b"\r" in item or b"\n" in item):
|
|
1736
|
+
# CR and LF end the command line on the wire, so an argument
|
|
1737
|
+
# carrying them would be run as extra commands. A literal can
|
|
1738
|
+
# hold them, which is what the 8-bit path already sends.
|
|
1739
|
+
raise ValueError(
|
|
1740
|
+
"CR and LF are not allowed in command arguments; "
|
|
1741
|
+
"wrap the value in imapclient.literal to send it as a literal"
|
|
1742
|
+
)
|
|
1716
1743
|
|
|
1744
|
+
line = []
|
|
1745
|
+
for item, is_last in _iter_with_last(prefix + args):
|
|
1717
1746
|
if _is8bit(item):
|
|
1718
1747
|
# If a line was already started send it
|
|
1719
1748
|
if line:
|
|
@@ -1872,6 +1901,8 @@ def _normalise_search_criteria(criteria, charset=None):
|
|
|
1872
1901
|
inner[0] = b"(" + inner[0]
|
|
1873
1902
|
inner[-1] = inner[-1] + b")"
|
|
1874
1903
|
out.extend(inner) # flatten
|
|
1904
|
+
elif isinstance(item, literal):
|
|
1905
|
+
out.append(item)
|
|
1875
1906
|
else:
|
|
1876
1907
|
out.append(_quoted.maybe(to_bytes(item, charset)))
|
|
1877
1908
|
return out
|
|
@@ -1883,10 +1914,13 @@ def _normalise_sort_criteria(criteria, charset=None):
|
|
|
1883
1914
|
return b"(" + b" ".join(to_bytes(item).upper() for item in criteria) + b")"
|
|
1884
1915
|
|
|
1885
1916
|
|
|
1886
|
-
class
|
|
1917
|
+
class literal(bytes):
|
|
1887
1918
|
"""Hold message data that should always be sent as a literal."""
|
|
1888
1919
|
|
|
1889
1920
|
|
|
1921
|
+
_literal = literal # old private name, kept for callers that imported it
|
|
1922
|
+
|
|
1923
|
+
|
|
1890
1924
|
class _quoted(bytes):
|
|
1891
1925
|
"""
|
|
1892
1926
|
This class holds a quoted bytes value which provides access to the
|
|
@@ -1979,7 +2013,7 @@ def as_triplets(items):
|
|
|
1979
2013
|
|
|
1980
2014
|
|
|
1981
2015
|
def _is8bit(data):
|
|
1982
|
-
return isinstance(data,
|
|
2016
|
+
return isinstance(data, literal) or any(b > 127 for b in data)
|
|
1983
2017
|
|
|
1984
2018
|
|
|
1985
2019
|
def _iter_with_last(items):
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "IMAPClient"
|
|
3
3
|
description = "Easy-to-use, Pythonic and complete IMAP client library"
|
|
4
|
-
version = "4.
|
|
4
|
+
version = "4.2.0"
|
|
5
|
+
license = {text = "BSD-3-Clause"}
|
|
5
6
|
authors = [
|
|
6
7
|
{name = "Menno Finlay-Smits", email = "hello@menno.io"},
|
|
7
8
|
]
|
|
@@ -46,6 +47,7 @@ requires = ["setuptools>=61.0"]
|
|
|
46
47
|
build-backend = "setuptools.build_meta"
|
|
47
48
|
|
|
48
49
|
[tool.setuptools]
|
|
50
|
+
license-files = ["COPYING", "AUTHORS.rst"]
|
|
49
51
|
packages = ["imapclient"]
|
|
50
52
|
|
|
51
53
|
[tool.setuptools.package-data]
|
|
@@ -15,18 +15,59 @@ from unittest.mock import Mock, patch, sentinel
|
|
|
15
15
|
from imapclient.exceptions import CapabilityError, IMAPClientError, ProtocolError
|
|
16
16
|
from imapclient.fixed_offset import FixedOffset
|
|
17
17
|
from imapclient.imapclient import (
|
|
18
|
-
_literal,
|
|
19
18
|
_parse_quota,
|
|
19
|
+
)
|
|
20
|
+
from imapclient.imapclient import IMAPClient as RealIMAPClient
|
|
21
|
+
from imapclient.imapclient import (
|
|
20
22
|
IMAPlibLoggerAdapter,
|
|
23
|
+
literal,
|
|
21
24
|
MailboxQuotaRoots,
|
|
22
25
|
Quota,
|
|
23
26
|
require_capability,
|
|
27
|
+
SocketTimeout,
|
|
24
28
|
)
|
|
25
29
|
from imapclient.testable_imapclient import TestableIMAPClient as IMAPClient
|
|
26
30
|
|
|
27
31
|
from .imapclient_test import IMAPClientTest
|
|
28
32
|
|
|
29
33
|
|
|
34
|
+
class TestCreateIMAP4(IMAPClientTest):
|
|
35
|
+
@patch("imapclient.imapclient.sys.version_info", (3, 8, 0))
|
|
36
|
+
@patch("imapclient.imapclient.tls.IMAP4_TLS")
|
|
37
|
+
@patch("imapclient.imapclient.imap4.IMAP4WithTimeout")
|
|
38
|
+
def test_python_38_does_not_pass_connect_timeout(self, plain_imap, tls_imap):
|
|
39
|
+
self.client._timeout = SocketTimeout(None, 30)
|
|
40
|
+
self.client.ssl_context = sentinel.ssl_context
|
|
41
|
+
|
|
42
|
+
self.client.ssl = True
|
|
43
|
+
self.assertIs(RealIMAPClient._create_IMAP4(self.client), tls_imap.return_value)
|
|
44
|
+
tls_imap.assert_called_once_with("somehost", 993, sentinel.ssl_context)
|
|
45
|
+
plain_imap.assert_not_called()
|
|
46
|
+
|
|
47
|
+
self.client.ssl = False
|
|
48
|
+
self.assertIs(
|
|
49
|
+
RealIMAPClient._create_IMAP4(self.client), plain_imap.return_value
|
|
50
|
+
)
|
|
51
|
+
plain_imap.assert_called_once_with("somehost", 993)
|
|
52
|
+
|
|
53
|
+
@patch("imapclient.imapclient.sys.version_info", (3, 8, 0))
|
|
54
|
+
@patch("imapclient.imapclient.tls.IMAP4_TLS")
|
|
55
|
+
@patch("imapclient.imapclient.imap4.IMAP4WithTimeout")
|
|
56
|
+
def test_python_38_rejects_connect_timeout(self, plain_imap, tls_imap):
|
|
57
|
+
self.client._timeout = SocketTimeout(10, 30)
|
|
58
|
+
|
|
59
|
+
for use_ssl in (True, False):
|
|
60
|
+
with self.subTest(ssl=use_ssl):
|
|
61
|
+
self.client.ssl = use_ssl
|
|
62
|
+
with self.assertRaisesRegex(
|
|
63
|
+
ValueError, "connection timeout is not supported"
|
|
64
|
+
):
|
|
65
|
+
RealIMAPClient._create_IMAP4(self.client)
|
|
66
|
+
|
|
67
|
+
tls_imap.assert_not_called()
|
|
68
|
+
plain_imap.assert_not_called()
|
|
69
|
+
|
|
70
|
+
|
|
30
71
|
class TestListFolders(IMAPClientTest):
|
|
31
72
|
def test_list_folders(self):
|
|
32
73
|
self.client._imap._simple_command.return_value = ("OK", [b"something"])
|
|
@@ -416,11 +457,11 @@ class TestAppend(IMAPClientTest):
|
|
|
416
457
|
b'"foobar"',
|
|
417
458
|
b"(FLAG WAVE)",
|
|
418
459
|
b'"05-Apr-2009 11:00:05 +0200"',
|
|
419
|
-
|
|
460
|
+
literal(b"msg1"),
|
|
420
461
|
b"(FLAG WAVE)",
|
|
421
|
-
|
|
462
|
+
literal(b"msg2"),
|
|
422
463
|
b'"05-Apr-2009 11:00:05 +0200"',
|
|
423
|
-
|
|
464
|
+
literal(b"msg3"),
|
|
424
465
|
],
|
|
425
466
|
uid=False,
|
|
426
467
|
)
|
|
@@ -749,6 +790,40 @@ class TestIdleAndNoop(IMAPClientTest):
|
|
|
749
790
|
self.assertListEqual([(99, b"EXISTS")], responses)
|
|
750
791
|
|
|
751
792
|
|
|
793
|
+
class TestRawCommandRejectsControlCharacters(IMAPClientTest):
|
|
794
|
+
def setUp(self):
|
|
795
|
+
super().setUp()
|
|
796
|
+
self.client._imap.send = Mock()
|
|
797
|
+
self.client._cached_capabilities = (b"IMAP4REV1",)
|
|
798
|
+
|
|
799
|
+
def test_crlf_in_a_line_argument_is_rejected_before_sending(self):
|
|
800
|
+
criterion = b'x"\r\nX1 STORE 1:* +FLAGS (\\Deleted)\r\nX2 EXPUNGE'
|
|
801
|
+
|
|
802
|
+
with self.assertRaises(ValueError):
|
|
803
|
+
self.client._raw_command(b"SEARCH", [b"HEADER", b"Message-ID", criterion])
|
|
804
|
+
|
|
805
|
+
self.client._imap.send.assert_not_called()
|
|
806
|
+
|
|
807
|
+
def test_crlf_via_search_criteria_is_rejected_before_sending(self):
|
|
808
|
+
with self.assertRaises(ValueError):
|
|
809
|
+
self.client.search(["HEADER", "Message-ID", 'x"\r\nX1 NOOP'])
|
|
810
|
+
|
|
811
|
+
self.client._imap.send.assert_not_called()
|
|
812
|
+
|
|
813
|
+
def test_nul_is_rejected_even_inside_a_literal(self):
|
|
814
|
+
with self.assertRaises(ValueError):
|
|
815
|
+
self.client._raw_command(b"SEARCH", [b"TEXT", literal(b"a\x00b")])
|
|
816
|
+
|
|
817
|
+
self.client._imap.send.assert_not_called()
|
|
818
|
+
|
|
819
|
+
def test_crlf_inside_a_literal_is_allowed(self):
|
|
820
|
+
self.client._send_literal = Mock()
|
|
821
|
+
|
|
822
|
+
self.client._raw_command(b"SEARCH", [b"TEXT", literal(b"line one\r\nline two")])
|
|
823
|
+
|
|
824
|
+
self.client._send_literal.assert_called_once()
|
|
825
|
+
|
|
826
|
+
|
|
752
827
|
class TestDebugLogging(IMAPClientTest):
|
|
753
828
|
def test_IMAP_is_patched(self):
|
|
754
829
|
# Remove all logging handlers so that the order of tests does not
|
|
@@ -1006,7 +1081,7 @@ class TestRawCommand(IMAPClientTest):
|
|
|
1006
1081
|
self.client._cached_capabilities = (b"LITERAL+",)
|
|
1007
1082
|
|
|
1008
1083
|
typ, data = self.client._raw_command(
|
|
1009
|
-
b"APPEND", [b"\xff",
|
|
1084
|
+
b"APPEND", [b"\xff", literal(b"hello")], uid=False
|
|
1010
1085
|
)
|
|
1011
1086
|
self.assertEqual(typ, "OK")
|
|
1012
1087
|
self.assertEqual(data, ["done"])
|
|
@@ -1020,7 +1095,7 @@ class TestRawCommand(IMAPClientTest):
|
|
|
1020
1095
|
|
|
1021
1096
|
typ, data = self.client._raw_command(
|
|
1022
1097
|
b"APPEND",
|
|
1023
|
-
[b"\xff",
|
|
1098
|
+
[b"\xff", literal(b"hello"), b"TEXT", literal(b"test")],
|
|
1024
1099
|
uid=False,
|
|
1025
1100
|
)
|
|
1026
1101
|
self.assertEqual(typ, "OK")
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# Released subject to the New BSD License
|
|
3
3
|
# Please see http://en.wikipedia.org/wiki/BSD_licenses
|
|
4
4
|
|
|
5
|
+
import sys
|
|
5
6
|
import unittest
|
|
6
7
|
from unittest.mock import Mock, patch, sentinel
|
|
7
8
|
|
|
@@ -22,6 +23,9 @@ class TestInit(unittest.TestCase):
|
|
|
22
23
|
self.imaplib = patcher.start()
|
|
23
24
|
self.addCleanup(patcher.stop)
|
|
24
25
|
|
|
26
|
+
@unittest.skipIf(
|
|
27
|
+
sys.version_info < (3, 9), "connection timeouts require Python 3.9+"
|
|
28
|
+
)
|
|
25
29
|
def test_plain(self):
|
|
26
30
|
fakeIMAP4 = Mock()
|
|
27
31
|
self.imap4.IMAP4WithTimeout.return_value = fakeIMAP4
|
|
@@ -36,6 +40,9 @@ class TestInit(unittest.TestCase):
|
|
|
36
40
|
self.assertEqual(imap.ssl_context, None)
|
|
37
41
|
self.assertEqual(imap.stream, False)
|
|
38
42
|
|
|
43
|
+
@unittest.skipIf(
|
|
44
|
+
sys.version_info < (3, 9), "connection timeouts require Python 3.9+"
|
|
45
|
+
)
|
|
39
46
|
def test_plain_SocketTimeout(self):
|
|
40
47
|
fakeIMAP4 = Mock()
|
|
41
48
|
self.imap4.IMAP4WithTimeout.return_value = fakeIMAP4
|
|
@@ -51,6 +58,9 @@ class TestInit(unittest.TestCase):
|
|
|
51
58
|
"1.2.3.4", 143, sentinel.connect_timeout
|
|
52
59
|
)
|
|
53
60
|
|
|
61
|
+
@unittest.skipIf(
|
|
62
|
+
sys.version_info < (3, 9), "connection timeouts require Python 3.9+"
|
|
63
|
+
)
|
|
54
64
|
def test_SSL(self):
|
|
55
65
|
fakeIMAP4_TLS = Mock()
|
|
56
66
|
self.tls.IMAP4_TLS.return_value = fakeIMAP4_TLS
|
|
@@ -69,6 +79,9 @@ class TestInit(unittest.TestCase):
|
|
|
69
79
|
self.assertEqual(imap.ssl_context, sentinel.context)
|
|
70
80
|
self.assertEqual(imap.stream, False)
|
|
71
81
|
|
|
82
|
+
@unittest.skipIf(
|
|
83
|
+
sys.version_info < (3, 9), "connection timeouts require Python 3.9+"
|
|
84
|
+
)
|
|
72
85
|
def test_SSL_SocketTimeout(self):
|
|
73
86
|
fakeIMAP4_TLS = Mock()
|
|
74
87
|
self.tls.IMAP4_TLS.return_value = fakeIMAP4_TLS
|
|
@@ -9,6 +9,7 @@ from imapclient.imapclient import (
|
|
|
9
9
|
_normalise_search_criteria,
|
|
10
10
|
_quoted,
|
|
11
11
|
join_message_ids,
|
|
12
|
+
literal,
|
|
12
13
|
normalise_text_list,
|
|
13
14
|
seq_to_parenstr,
|
|
14
15
|
seq_to_parenstr_upper,
|
|
@@ -139,6 +140,10 @@ class Test_normalise_search_criteria(unittest.TestCase):
|
|
|
139
140
|
def test_quoting(self):
|
|
140
141
|
self.check(["foo bar"], None, [_quoted(b'"foo bar"')])
|
|
141
142
|
|
|
143
|
+
def test_literal_is_not_quoted(self):
|
|
144
|
+
value = literal(b"line one\r\nline two")
|
|
145
|
+
self.check(["TEXT", value], None, [b"TEXT", value])
|
|
146
|
+
|
|
142
147
|
def test_ints(self):
|
|
143
148
|
self.check(["modseq", 500], None, [b"modseq", b"500"])
|
|
144
149
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|