#21815: violate IMAP RFC to be compatible with, e.g., gmail

and others, including imaplib's own behavior.  I'm applying this only to 3.6
because there's a potential backward compatibility concern: if there are
servers that include ] characters in the 'text' portion of their imap
responses, this code change could introduce a new bug.

Patch by Lita Cho, reviewed by Jessica McKellar, Berker Peksag, Maciej Szulik,
silentghost, and me (I fleshed out the comments with the additional
info/concerns.)
This commit is contained in:
R David Murray 2016-01-02 17:18:34 -05:00
parent 01759d5554
commit 317f64f048
4 changed files with 73 additions and 1 deletions

View file

@ -242,6 +242,55 @@ class ThreadedNetworkedTests(unittest.TestCase):
client = self.imap_class(*server.server_address)
client.shutdown()
@reap_threads
def test_bracket_flags(self):
# This violates RFC 3501, which disallows ']' characters in tag names,
# but imaplib has allowed producing such tags forever, other programs
# also produce them (eg: OtherInbox's Organizer app as of 20140716),
# and Gmail, for example, accepts them and produces them. So we
# support them. See issue #21815.
class BracketFlagHandler(SimpleIMAPHandler):
def handle(self):
self.flags = ['Answered', 'Flagged', 'Deleted', 'Seen', 'Draft']
super().handle()
def cmd_AUTHENTICATE(self, tag, args):
self._send_textline('+')
self.server.response = yield
self._send_tagged(tag, 'OK', 'FAKEAUTH successful')
def cmd_SELECT(self, tag, args):
flag_msg = ' \\'.join(self.flags)
self._send_line(('* FLAGS (%s)' % flag_msg).encode('ascii'))
self._send_line(b'* 2 EXISTS')
self._send_line(b'* 0 RECENT')
msg = ('* OK [PERMANENTFLAGS %s \\*)] Flags permitted.'
% flag_msg)
self._send_line(msg.encode('ascii'))
self._send_tagged(tag, 'OK', '[READ-WRITE] SELECT completed.')
def cmd_STORE(self, tag, args):
new_flags = args[2].strip('(').strip(')').split()
self.flags.extend(new_flags)
flags_msg = '(FLAGS (%s))' % ' \\'.join(self.flags)
msg = '* %s FETCH %s' % (args[0], flags_msg)
self._send_line(msg.encode('ascii'))
self._send_tagged(tag, 'OK', 'STORE completed.')
with self.reaped_pair(BracketFlagHandler) as (server, client):
code, data = client.authenticate('MYAUTH', lambda x: b'fake')
self.assertEqual(code, 'OK')
self.assertEqual(server.response, b'ZmFrZQ==\r\n')
client.select('test')
typ, [data] = client.store(b'1', "+FLAGS", "[test]")
self.assertIn(b'[test]', data)
client.select('test')
typ, [data] = client.response('PERMANENTFLAGS')
self.assertIn(b'[test]', data)
@reap_threads
def test_issue5949(self):