# We compile these in _mode_xxx.
_Literal = br'.*{(?P<size>\d+)}$'
_Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?'
+# Only NUL, CR and LF are unsafe (they cannot be represented even in
+# a quoted string); other control characters are sent quoted.
+_control_chars = re.compile(b'[\x00\r\n]')
_non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]')
_non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]')
_quoted = re.compile(br'"(?:[^"\\]|\\.)*+"')
if arg is None: continue
if isinstance(arg, str):
arg = bytes(arg, self._encoding)
+ if _control_chars.search(arg):
+ raise ValueError("NUL, CR and LF not allowed in commands")
data = data + b' ' + arg
literal = self.literal
with self.assertRaises(AttributeError):
client.NONEXISTENT
+ def test_control_characters(self):
+ client, server = self._setup(SimpleIMAPHandler)
+ client.login('user', 'pass')
+ for c in '\0\r\n':
+ with self.assertRaises(ValueError):
+ client.select(f'a{c}b')
+ # Other control characters are valid in a quoted string and can
+ # occur in mailbox names returned by the server, so the client
+ # must be able to send them back.
+ for c in support.control_characters_c0():
+ if c in '\0\r\n':
+ continue
+ typ, _ = client.select(f'a{c}b')
+ self.assertEqual(typ, 'OK')
+ self.assertEqual(server.is_selected, [f'"a{c}b"'])
+
# property tests
def test_file_property_should_not_be_accessed(self):