summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/poplib.rst8
-rw-r--r--Lib/poplib.py30
-rw-r--r--Lib/test/test_poplib.py16
-rw-r--r--Misc/NEWS3
4 files changed, 57 insertions, 0 deletions
diff --git a/Doc/library/poplib.rst b/Doc/library/poplib.rst
index 01f680e..2eb3b72 100644
--- a/Doc/library/poplib.rst
+++ b/Doc/library/poplib.rst
@@ -97,6 +97,14 @@ An :class:`POP3` instance has the following methods:
Returns the greeting string sent by the POP3 server.
+.. method:: POP3.capa()
+
+ Query the server's capabilities as specified in :rfc:`2449`.
+ Returns a dictionary in the form ``{'name': ['param'...]}``.
+
+ .. versionadded:: 3.4
+
+
.. method:: POP3.user(username)
Send user command, response should indicate that a password is required.
diff --git a/Lib/poplib.py b/Lib/poplib.py
index 094aaa1..ccb28e5 100644
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -55,6 +55,7 @@ class POP3:
APOP name digest apop(name, digest)
TOP msg n top(msg, n)
UIDL [msg] uidl(msg = None)
+ CAPA capa()
Raises one exception: 'error_proto'.
@@ -322,6 +323,35 @@ class POP3:
return self._shortcmd('UIDL %s' % which)
return self._longcmd('UIDL')
+
+ def capa(self):
+ """Return server capabilities (RFC 2449) as a dictionary
+ >>> c=poplib.POP3('localhost')
+ >>> c.capa()
+ {'IMPLEMENTATION': ['Cyrus', 'POP3', 'server', 'v2.2.12'],
+ 'TOP': [], 'LOGIN-DELAY': ['0'], 'AUTH-RESP-CODE': [],
+ 'EXPIRE': ['NEVER'], 'USER': [], 'STLS': [], 'PIPELINING': [],
+ 'UIDL': [], 'RESP-CODES': []}
+ >>>
+
+ Really, according to RFC 2449, the cyrus folks should avoid
+ having the implementation splitted into multiple arguments...
+ """
+ def _parsecap(line):
+ lst = line.decode('ascii').split()
+ return lst[0], lst[1:]
+
+ caps = {}
+ try:
+ resp = self._longcmd('CAPA')
+ rawcaps = resp[1]
+ for capline in rawcaps:
+ capnm, capargs = _parsecap(capline)
+ caps[capnm] = capargs
+ except error_proto as _err:
+ raise error_proto('-ERR CAPA not supported by server')
+ return caps
+
try:
import ssl
except ImportError:
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
index c0929a0..8fe0c4cb 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -33,6 +33,8 @@ line3\r\n\
class DummyPOP3Handler(asynchat.async_chat):
+ CAPAS = {'UIDL': [], 'IMPLEMENTATION': ['python-testlib-pop-server']}
+
def __init__(self, conn):
asynchat.async_chat.__init__(self, conn)
self.set_terminator(b"\r\n")
@@ -112,6 +114,16 @@ class DummyPOP3Handler(asynchat.async_chat):
self.push('+OK closing.')
self.close_when_done()
+ def cmd_capa(self, arg):
+ self.push('+OK Capability list follows')
+ if self.CAPAS:
+ for cap, params in self.CAPAS.items():
+ _ln = [cap]
+ if params:
+ _ln.extend(params)
+ self.push(' '.join(_ln))
+ self.push('.')
+
class DummyPOP3Server(asyncore.dispatcher, threading.Thread):
@@ -232,6 +244,10 @@ class TestPOP3Class(TestCase):
self.client.uidl()
self.client.uidl('foo')
+ def test_capa(self):
+ capa = self.client.capa()
+ self.assertTrue('IMPLEMENTATION' in capa.keys())
+
def test_quit(self):
resp = self.client.quit()
self.assertTrue(resp)
diff --git a/Misc/NEWS b/Misc/NEWS
index 917f4d5..7ddb33b 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -138,6 +138,9 @@ Core and Builtins
Library
-------
+- Issue #4473: Add a POP3.capa() method to query the capabilities advertised
+ by the POP3 server. Patch by Lorenzo Catucci.
+
- Issue #4473: Ensure the socket is shutdown cleanly in POP3.close().
Patch by Lorenzo Catucci.