summaryrefslogtreecommitdiffstats
path: root/Lib/imaplib.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/imaplib.py')
-rw-r--r--Lib/imaplib.py167
1 files changed, 90 insertions, 77 deletions
diff --git a/Lib/imaplib.py b/Lib/imaplib.py
index 129de06..8734a84 100644
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -22,9 +22,9 @@ Public functions: Internaldate2tuple
__version__ = "2.58"
-import binascii, os, random, re, socket, sys, time
+import binascii, random, re, socket, subprocess, sys, time
-__all__ = ["IMAP4", "IMAP4_SSL", "IMAP4_stream", "Internaldate2tuple",
+__all__ = ["IMAP4", "IMAP4_stream", "Internaldate2tuple",
"Int2AP", "ParseFlags", "Time2Internaldate"]
# Globals
@@ -226,8 +226,7 @@ class IMAP4:
"""
self.host = host
self.port = port
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.connect((host, port))
+ self.sock = socket.create_connection((host, port))
self.file = self.sock.makefile('rb')
@@ -727,7 +726,7 @@ class IMAP4:
def thread(self, threading_algorithm, charset, *search_criteria):
"""IMAPrev1 extension THREAD command.
- (type, [data]) = <instance>.thread(threading_alogrithm, charset, search_criteria, ...)
+ (type, [data]) = <instance>.thread(threading_algorithm, charset, search_criteria, ...)
"""
name = 'THREAD'
typ, dat = self._simple_command(name, threading_algorithm, charset, *search_criteria)
@@ -746,11 +745,13 @@ class IMAP4:
if not command in Commands:
raise self.error("Unknown IMAP4 UID command: %s" % command)
if self.state not in Commands[command]:
- raise self.error('command %s illegal in state %s'
- % (command, self.state))
+ raise self.error("command %s illegal in state %s, "
+ "only allowed in states %s" %
+ (command, self.state,
+ ', '.join(Commands[command])))
name = 'UID'
typ, dat = self._simple_command(name, command, *args)
- if command in ('SEARCH', 'SORT'):
+ if command in ('SEARCH', 'SORT', 'THREAD'):
name = command
else:
name = 'FETCH'
@@ -811,8 +812,10 @@ class IMAP4:
if self.state not in Commands[name]:
self.literal = None
- raise self.error(
- 'command %s illegal in state %s' % (name, self.state))
+ raise self.error("command %s illegal in state %s, "
+ "only allowed in states %s" %
+ (name, self.state,
+ ', '.join(Commands[name])))
for typ in ('OK', 'NO', 'BAD'):
if typ in self.untagged_responses:
@@ -998,6 +1001,8 @@ class IMAP4:
raise self.abort('socket error: EOF')
# Protocol mandates all lines terminated by CRLF
+ if not line.endswith('\r\n'):
+ raise self.abort('socket error: unterminated line')
line = line[:-2]
if __debug__:
@@ -1107,95 +1112,98 @@ class IMAP4:
-class IMAP4_SSL(IMAP4):
+try:
+ import ssl
+except ImportError:
+ pass
+else:
+ class IMAP4_SSL(IMAP4):
- """IMAP4 client class over SSL connection
+ """IMAP4 client class over SSL connection
- Instantiate with: IMAP4_SSL([host[, port[, keyfile[, certfile]]]])
+ Instantiate with: IMAP4_SSL([host[, port[, keyfile[, certfile]]]])
- host - host's name (default: localhost);
- port - port number (default: standard IMAP4 SSL port).
- keyfile - PEM formatted file that contains your private key (default: None);
- certfile - PEM formatted certificate chain file (default: None);
+ host - host's name (default: localhost);
+ port - port number (default: standard IMAP4 SSL port).
+ keyfile - PEM formatted file that contains your private key (default: None);
+ certfile - PEM formatted certificate chain file (default: None);
- for more documentation see the docstring of the parent class IMAP4.
- """
+ for more documentation see the docstring of the parent class IMAP4.
+ """
- def __init__(self, host = '', port = IMAP4_SSL_PORT, keyfile = None, certfile = None):
- self.keyfile = keyfile
- self.certfile = certfile
- IMAP4.__init__(self, host, port)
+ def __init__(self, host = '', port = IMAP4_SSL_PORT, keyfile = None, certfile = None):
+ self.keyfile = keyfile
+ self.certfile = certfile
+ IMAP4.__init__(self, host, port)
- def open(self, host = '', port = IMAP4_SSL_PORT):
- """Setup connection to remote server on "host:port".
- (default: localhost:standard IMAP4 SSL port).
- This connection will be used by the routines:
- read, readline, send, shutdown.
- """
- self.host = host
- self.port = port
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.connect((host, port))
- self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
+ def open(self, host = '', port = IMAP4_SSL_PORT):
+ """Setup connection to remote server on "host:port".
+ (default: localhost:standard IMAP4 SSL port).
+ This connection will be used by the routines:
+ read, readline, send, shutdown.
+ """
+ self.host = host
+ self.port = port
+ self.sock = socket.create_connection((host, port))
+ self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
- def read(self, size):
- """Read 'size' bytes from remote."""
- # sslobj.read() sometimes returns < size bytes
- chunks = []
- read = 0
- while read < size:
- data = self.sslobj.read(min(size-read, 16384))
- read += len(data)
- chunks.append(data)
+ def read(self, size):
+ """Read 'size' bytes from remote."""
+ # sslobj.read() sometimes returns < size bytes
+ chunks = []
+ read = 0
+ while read < size:
+ data = self.sslobj.read(min(size-read, 16384))
+ read += len(data)
+ chunks.append(data)
- return ''.join(chunks)
+ return ''.join(chunks)
- def readline(self):
- """Read line from remote."""
- # NB: socket.ssl needs a "readline" method, or perhaps a "makefile" method.
- line = []
- while 1:
- char = self.sslobj.read(1)
- line.append(char)
- if char == "\n": return ''.join(line)
+ def readline(self):
+ """Read line from remote."""
+ line = []
+ while 1:
+ char = self.sslobj.read(1)
+ line.append(char)
+ if char in ("\n", ""): return ''.join(line)
- def send(self, data):
- """Send data to remote."""
- # NB: socket.ssl needs a "sendall" method to match socket objects.
- bytes = len(data)
- while bytes > 0:
- sent = self.sslobj.write(data)
- if sent == bytes:
- break # avoid copy
- data = data[sent:]
- bytes = bytes - sent
+ def send(self, data):
+ """Send data to remote."""
+ bytes = len(data)
+ while bytes > 0:
+ sent = self.sslobj.write(data)
+ if sent == bytes:
+ break # avoid copy
+ data = data[sent:]
+ bytes = bytes - sent
- def shutdown(self):
- """Close I/O established in "open"."""
- self.sock.close()
+ def shutdown(self):
+ """Close I/O established in "open"."""
+ self.sock.close()
- def socket(self):
- """Return socket instance used to connect to IMAP4 server.
+ def socket(self):
+ """Return socket instance used to connect to IMAP4 server.
- socket = <instance>.socket()
- """
- return self.sock
+ socket = <instance>.socket()
+ """
+ return self.sock
- def ssl(self):
- """Return SSLObject instance used to communicate with the IMAP4 server.
+ def ssl(self):
+ """Return SSLObject instance used to communicate with the IMAP4 server.
- ssl = <instance>.socket.ssl()
- """
- return self.sslobj
+ ssl = ssl.wrap_socket(<instance>.socket)
+ """
+ return self.sslobj
+ __all__.append("IMAP4_SSL")
class IMAP4_stream(IMAP4):
@@ -1204,7 +1212,7 @@ class IMAP4_stream(IMAP4):
Instantiate with: IMAP4_stream(command)
- where "command" is a string that can be passed to os.popen2()
+ where "command" is a string that can be passed to subprocess.Popen()
for more documentation see the docstring of the parent class IMAP4.
"""
@@ -1224,7 +1232,11 @@ class IMAP4_stream(IMAP4):
self.port = None
self.sock = None
self.file = None
- self.writefile, self.readfile = os.popen2(self.command)
+ self.process = subprocess.Popen(self.command,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ shell=True, close_fds=True)
+ self.writefile = self.process.stdin
+ self.readfile = self.process.stdout
def read(self, size):
@@ -1247,6 +1259,7 @@ class IMAP4_stream(IMAP4):
"""Close I/O established in "open"."""
self.readfile.close()
self.writefile.close()
+ self.process.wait()