]> code.delx.au - offlineimap/blobdiff - offlineimap/imaplib.py
Check all resolved addresses [deb #413030]
[offlineimap] / offlineimap / imaplib.py
index f344ab2f314193dc75c8b0400a2125a03ae52f87..a4bdc22d6b81273afb25f036987e72e95758dcb8 100644 (file)
@@ -5,6 +5,7 @@ Based on RFC 2060.
 Public class:           IMAP4
 Public variable:        Debug
 Public functions:       Internaldate2tuple
+                        Internaldate2epoch
                         Int2AP
                         ParseFlags
                         Time2Internaldate
@@ -24,7 +25,7 @@ __version__ = "2.52"
 import binascii, re, socket, time, random, sys, os
 from offlineimap.ui import UIBase
 
-__all__ = ["IMAP4", "Internaldate2tuple",
+__all__ = ["IMAP4", "Internaldate2tuple", "Internaldate2epoch",
            "Int2AP", "ParseFlags", "Time2Internaldate"]
 
 #       Globals
@@ -78,7 +79,7 @@ Commands = {
 Continuation = re.compile(r'\+( (?P<data>.*))?')
 Flags = re.compile(r'.*FLAGS \((?P<flags>[^\)]*)\)')
 InternalDate = re.compile(r'.*INTERNALDATE "'
-        r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9])'
+        r'(?P<day>[ 0123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9])'
         r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
         r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
         r'"')
@@ -136,7 +137,7 @@ class IMAP4:
     class abort(error): pass        # Service errors - close and retry
     class readonly(abort): pass     # Mailbox status changed to READ-ONLY
 
-    mustquote = re.compile(r"[^\w!#$%&'*+,.:;<=>?^`|~-]")
+    mustquote = re.compile(r"[^\w!#$%&'+,.:;<=>?^`|~-]")
 
     def __init__(self, host = '', port = IMAP4_PORT):
         self.debug = Debug
@@ -217,15 +218,26 @@ class IMAP4:
         """
         self.host = host
         self.port = port
-        #This connects to the first ip found ipv4/ipv6
-        #Added by Adriaan Peeters <apeeters@lashout.net> based on a socket
-        #example from the python documentation:
-        #http://www.python.org/doc/lib/socket-example.html
         res = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
                                  socket.SOCK_STREAM)
-        af, socktype, proto, canonname, sa = res[0]
         self.sock = socket.socket(af, socktype, proto)
-        self.sock.connect(sa)
+
+        # Try each address returned by getaddrinfo in turn until we
+        # manage to connect to one.
+        # Try all the addresses in turn until we connect()
+        last_error = 0
+        for remote in res:
+            af, socktype, proto, canonname, sa = remote
+            self.sock = socket.socket(af, socktype, proto)
+            last_error = self.sock.connect_ex(sa)
+            print af
+            if last_error == 0:
+                break
+            else:
+                self.sock.close()
+        if last_error != 0:
+            # FIXME
+            raise socket.error(last_error)
         self.file = self.sock.makefile('rb')
 
     def read(self, size):
@@ -1131,9 +1143,20 @@ class IMAP4_SSL(IMAP4):
         #http://www.python.org/doc/lib/socket-example.html
         res = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
                                  socket.SOCK_STREAM)
-        af, socktype, proto, canonname, sa = res[0]
-        self.sock = socket.socket(af, socktype, proto)
-        self.sock.connect(sa)
+        # Try all the addresses in turn until we connect()
+        last_error = 0
+        for remote in res:
+            af, socktype, proto, canonname, sa = remote
+            self.sock = socket.socket(af, socktype, proto)
+            last_error = self.sock.connect_ex(sa)
+            print af
+            if last_error == 0:
+                break
+            else:
+                self.sock.close()
+        if last_error != 0:
+            # FIXME
+            raise socket.error(last_error)
         if sys.version_info[0] <= 2 and sys.version_info[1] <= 2:
             self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
         else:
@@ -1230,10 +1253,10 @@ class _Authenticator:
 Mon2num = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
         'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
 
-def Internaldate2tuple(resp):
+def Internaldate2epoch(resp):
     """Convert IMAP4 INTERNALDATE to UT.
 
-    Returns Python time module tuple.
+    Returns seconds since the epoch.
     """
 
     mo = InternalDate.match(resp)
@@ -1259,7 +1282,16 @@ def Internaldate2tuple(resp):
 
     tt = (year, mon, day, hour, min, sec, -1, -1, -1)
 
-    utc = time.mktime(tt)
+    return time.mktime(tt)
+
+
+def Internaldate2tuple(resp):
+    """Convert IMAP4 INTERNALDATE to UT.
+
+    Returns Python time module tuple.
+    """
+
+    utc = Internaldate2epoch(resp)
 
     # Following is necessary because the time module has no 'mkgmtime'.
     # 'mktime' assumes arg in local timezone, so adds timezone/altzone.