Index: Lib/imaplib.py =================================================================== --- Lib/imaplib.py (révision 86383) +++ Lib/imaplib.py (copie de travail) @@ -24,6 +24,12 @@ import binascii, random, re, socket, subprocess, sys, time +try: + import ssl + HAVE_SSL = True +except ImportError: + HAVE_SSL = False + __all__ = ["IMAP4", "IMAP4_stream", "Internaldate2tuple", "Int2AP", "ParseFlags", "Time2Internaldate"] @@ -71,6 +77,7 @@ 'SETANNOTATION':('AUTH', 'SELECTED'), 'SETQUOTA': ('AUTH', 'SELECTED'), 'SORT': ('SELECTED',), + 'STARTTLS': ('NONAUTH',), 'STATUS': ('AUTH', 'SELECTED'), 'STORE': ('SELECTED',), 'SUBSCRIBE': ('AUTH', 'SELECTED'), @@ -156,6 +163,7 @@ self.continuation_response = '' # Last continuation response self.is_readonly = False # READ-ONLY desired state self.tagnum = 0 + self._tls_established = False # Open socket to server. @@ -705,6 +713,33 @@ return self._untagged_response(typ, dat, name) + def starttls(self, ssl_context=None): + name = 'STARTTLS' + if not HAVE_SSL: + raise self.error('SSL support missing') + if self._tls_established: + raise self.abort('TLS session already established') + if name not in self.capabilities: + raise self.abort('TLS not supported by server') + # Generate a default SSL context if none was passed. + if ssl_context is None: + ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + # SSLv2 considered harmful. + ssl_context.options |= ssl.OP_NO_SSLv2 + typ, dat = self._simple_command(name) + if typ == 'OK': + self.sock = ssl_context.wrap_socket(self.sock) + self.file = self.sock.makefile('rb') + self._tls_established = True + typ, dat = self.capability() + if dat == [None]: + raise self.error('no CAPABILITY response from server') + self.capabilities = tuple(dat[-1].upper().split()) + else: + raise self.error("Couldn't establish TLS session") + return self._untagged_response(typ, dat, name) + + def status(self, mailbox, names): """Request named status conditions for mailbox. @@ -1116,12 +1151,8 @@ n -= 1 +if HAVE_SSL: -try: - import ssl -except ImportError: - pass -else: class IMAP4_SSL(IMAP4): """IMAP4 client class over SSL connection Index: Lib/test/test_imaplib.py =================================================================== --- Lib/test/test_imaplib.py (révision 86383) +++ Lib/test/test_imaplib.py (copie de travail) @@ -209,8 +209,6 @@ def test_logincapa(self): self.assertTrue('LOGINDISABLED' in self.server.capabilities) - - def test_anonlogin(self): self.assertTrue('AUTH=ANONYMOUS' in self.server.capabilities) rs = self.server.login(self.username, self.password) self.assertEqual(rs[0], 'OK') @@ -222,6 +220,18 @@ @unittest.skipUnless(ssl, "SSL not available") +class RemoteIMAP_STARTTLSTest(RemoteIMAPTest): + + def setUp(self): + super().setUp() + rs = self.server.starttls() + self.assertEqual(rs[0], 'OK') + + def test_logincapa(self): + self.assertFalse('LOGINDISABLED' in self.server.capabilities) + + +@unittest.skipUnless(ssl, "SSL not available") class RemoteIMAP_SSLTest(RemoteIMAPTest): port = 993 imap_class = IMAP4_SSL @@ -243,7 +253,7 @@ raise support.TestFailed("Can't read certificate files!") tests.extend([ ThreadedNetworkedTests, ThreadedNetworkedTestsSSL, - RemoteIMAPTest, RemoteIMAP_SSLTest, + RemoteIMAPTest, RemoteIMAP_SSLTest, RemoteIMAP_STARTTLSTest, ]) support.run_unittest(*tests)