diff options
Diffstat (limited to 'Lib/imaplib.py')
-rw-r--r-- | Lib/imaplib.py | 80 |
1 files changed, 64 insertions, 16 deletions
diff --git a/Lib/imaplib.py b/Lib/imaplib.py index fc1e20a27dc..1022e77c4f6 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -24,6 +24,12 @@ __version__ = "2.58" import binascii, errno, 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 @@ Commands = { 'SETANNOTATION':('AUTH', 'SELECTED'), 'SETQUOTA': ('AUTH', 'SELECTED'), 'SORT': ('SELECTED',), + 'STARTTLS': ('NONAUTH',), 'STATUS': ('AUTH', 'SELECTED'), 'STORE': ('SELECTED',), 'SUBSCRIBE': ('AUTH', 'SELECTED'), @@ -156,11 +163,23 @@ class IMAP4: 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. self.open(host, port) + try: + self._connect() + except Exception: + try: + self.shutdown() + except socket.error: + pass + raise + + + def _connect(self): # Create unique tag for this session, # and compile tagged response matcher. @@ -188,13 +207,7 @@ class IMAP4: else: raise self.error(self.welcome) - typ, dat = self.capability() - if dat == [None]: - raise self.error('no CAPABILITY response from server') - dat = str(dat[-1], "ASCII") - dat = dat.upper() - self.capabilities = tuple(dat.split()) - + self._get_capabilities() if __debug__: if self.debug >= 3: self._mesg('CAPABILITIES: %r' % (self.capabilities,)) @@ -711,6 +724,30 @@ class IMAP4: 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 + self._get_capabilities() + 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. @@ -921,6 +958,15 @@ class IMAP4: return typ, data + def _get_capabilities(self): + typ, dat = self.capability() + if dat == [None]: + raise self.error('no CAPABILITY response from server') + dat = str(dat[-1], "ASCII") + dat = dat.upper() + self.capabilities = tuple(dat.split()) + + def _get_response(self): # Read response and store. @@ -1125,12 +1171,8 @@ class IMAP4: n -= 1 +if HAVE_SSL: -try: - import ssl -except ImportError: - pass -else: class IMAP4_SSL(IMAP4): """IMAP4 client class over SSL connection @@ -1270,9 +1312,10 @@ Mon2num = {b'Jan': 1, b'Feb': 2, b'Mar': 3, b'Apr': 4, b'May': 5, b'Jun': 6, b'Jul': 7, b'Aug': 8, b'Sep': 9, b'Oct': 10, b'Nov': 11, b'Dec': 12} def Internaldate2tuple(resp): - """Convert IMAP4 INTERNALDATE to UT. + """Parse an IMAP4 INTERNALDATE string. - Returns Python time module tuple. + Return corresponding local time. The return value is a + time.struct_time tuple or None if the string has wrong format. """ mo = InternalDate.match(resp) @@ -1339,9 +1382,14 @@ def ParseFlags(resp): def Time2Internaldate(date_time): - """Convert 'date_time' to IMAP4 INTERNALDATE representation. + """Convert date_time to IMAP4 INTERNALDATE representation. - Return string in form: '"DD-Mmm-YYYY HH:MM:SS +HHMM"' + Return string in form: '"DD-Mmm-YYYY HH:MM:SS +HHMM"'. The + date_time argument can be a number (int or float) represening + seconds since epoch (as returned by time.time()), a 9-tuple + representing local time (as returned by time.localtime()), or a + double-quoted string. In the last case, it is assumed to already + be in the correct format. """ if isinstance(date_time, (int, float)): |