Issue #4473: Add a POP3.capa() method to query the capabilities advertised by the POP3 server.
Patch by Lorenzo Catucci.
This commit is contained in:
parent
d89824b0e2
commit
25cee19beb
|
@ -97,6 +97,14 @@ An :class:`POP3` instance has the following methods:
|
||||||
Returns the greeting string sent by the POP3 server.
|
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)
|
.. method:: POP3.user(username)
|
||||||
|
|
||||||
Send user command, response should indicate that a password is required.
|
Send user command, response should indicate that a password is required.
|
||||||
|
|
|
@ -55,6 +55,7 @@ class POP3:
|
||||||
APOP name digest apop(name, digest)
|
APOP name digest apop(name, digest)
|
||||||
TOP msg n top(msg, n)
|
TOP msg n top(msg, n)
|
||||||
UIDL [msg] uidl(msg = None)
|
UIDL [msg] uidl(msg = None)
|
||||||
|
CAPA capa()
|
||||||
|
|
||||||
Raises one exception: 'error_proto'.
|
Raises one exception: 'error_proto'.
|
||||||
|
|
||||||
|
@ -322,6 +323,35 @@ class POP3:
|
||||||
return self._shortcmd('UIDL %s' % which)
|
return self._shortcmd('UIDL %s' % which)
|
||||||
return self._longcmd('UIDL')
|
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:
|
try:
|
||||||
import ssl
|
import ssl
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -33,6 +33,8 @@ line3\r\n\
|
||||||
|
|
||||||
class DummyPOP3Handler(asynchat.async_chat):
|
class DummyPOP3Handler(asynchat.async_chat):
|
||||||
|
|
||||||
|
CAPAS = {'UIDL': [], 'IMPLEMENTATION': ['python-testlib-pop-server']}
|
||||||
|
|
||||||
def __init__(self, conn):
|
def __init__(self, conn):
|
||||||
asynchat.async_chat.__init__(self, conn)
|
asynchat.async_chat.__init__(self, conn)
|
||||||
self.set_terminator(b"\r\n")
|
self.set_terminator(b"\r\n")
|
||||||
|
@ -112,6 +114,16 @@ class DummyPOP3Handler(asynchat.async_chat):
|
||||||
self.push('+OK closing.')
|
self.push('+OK closing.')
|
||||||
self.close_when_done()
|
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):
|
class DummyPOP3Server(asyncore.dispatcher, threading.Thread):
|
||||||
|
|
||||||
|
@ -232,6 +244,10 @@ class TestPOP3Class(TestCase):
|
||||||
self.client.uidl()
|
self.client.uidl()
|
||||||
self.client.uidl('foo')
|
self.client.uidl('foo')
|
||||||
|
|
||||||
|
def test_capa(self):
|
||||||
|
capa = self.client.capa()
|
||||||
|
self.assertTrue('IMPLEMENTATION' in capa.keys())
|
||||||
|
|
||||||
def test_quit(self):
|
def test_quit(self):
|
||||||
resp = self.client.quit()
|
resp = self.client.quit()
|
||||||
self.assertTrue(resp)
|
self.assertTrue(resp)
|
||||||
|
|
|
@ -138,6 +138,9 @@ Core and Builtins
|
||||||
Library
|
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().
|
- Issue #4473: Ensure the socket is shutdown cleanly in POP3.close().
|
||||||
Patch by Lorenzo Catucci.
|
Patch by Lorenzo Catucci.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue