aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/mail/pop3client.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/mail/pop3client.py')
-rwxr-xr-xlib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/mail/pop3client.py706
1 files changed, 0 insertions, 706 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/mail/pop3client.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/mail/pop3client.py
deleted file mode 100755
index fe8f497e..00000000
--- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/mail/pop3client.py
+++ /dev/null
@@ -1,706 +0,0 @@
-# -*- test-case-name: twisted.mail.test.test_pop3client -*-
-# Copyright (c) 2001-2004 Divmod Inc.
-# Copyright (c) Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-"""
-POP3 client protocol implementation
-
-Don't use this module directly. Use twisted.mail.pop3 instead.
-
-@author: Jp Calderone
-"""
-
-import re
-
-from twisted.python import log
-from twisted.python.hashlib import md5
-from twisted.internet import defer
-from twisted.protocols import basic
-from twisted.protocols import policies
-from twisted.internet import error
-from twisted.internet import interfaces
-
-OK = '+OK'
-ERR = '-ERR'
-
-class POP3ClientError(Exception):
- """Base class for all exceptions raised by POP3Client.
- """
-
-class InsecureAuthenticationDisallowed(POP3ClientError):
- """Secure authentication was required but no mechanism could be found.
- """
-
-class TLSError(POP3ClientError):
- """
- Secure authentication was required but either the transport does
- not support TLS or no TLS context factory was supplied.
- """
-
-class TLSNotSupportedError(POP3ClientError):
- """
- Secure authentication was required but the server does not support
- TLS.
- """
-
-class ServerErrorResponse(POP3ClientError):
- """The server returned an error response to a request.
- """
- def __init__(self, reason, consumer=None):
- POP3ClientError.__init__(self, reason)
- self.consumer = consumer
-
-class LineTooLong(POP3ClientError):
- """The server sent an extremely long line.
- """
-
-class _ListSetter:
- # Internal helper. POP3 responses sometimes occur in the
- # form of a list of lines containing two pieces of data,
- # a message index and a value of some sort. When a message
- # is deleted, it is omitted from these responses. The
- # setitem method of this class is meant to be called with
- # these two values. In the cases where indexes are skipped,
- # it takes care of padding out the missing values with None.
- def __init__(self, L):
- self.L = L
- def setitem(self, (item, value)):
- diff = item - len(self.L) + 1
- if diff > 0:
- self.L.extend([None] * diff)
- self.L[item] = value
-
-
-def _statXform(line):
- # Parse a STAT response
- numMsgs, totalSize = line.split(None, 1)
- return int(numMsgs), int(totalSize)
-
-
-def _listXform(line):
- # Parse a LIST response
- index, size = line.split(None, 1)
- return int(index) - 1, int(size)
-
-
-def _uidXform(line):
- # Parse a UIDL response
- index, uid = line.split(None, 1)
- return int(index) - 1, uid
-
-def _codeStatusSplit(line):
- # Parse an +OK or -ERR response
- parts = line.split(' ', 1)
- if len(parts) == 1:
- return parts[0], ''
- return parts
-
-def _dotUnquoter(line):
- """
- C{'.'} characters which begin a line of a message are doubled to avoid
- confusing with the terminating C{'.\\r\\n'} sequence. This function
- unquotes them.
- """
- if line.startswith('..'):
- return line[1:]
- return line
-
-class POP3Client(basic.LineOnlyReceiver, policies.TimeoutMixin):
- """POP3 client protocol implementation class
-
- Instances of this class provide a convenient, efficient API for
- retrieving and deleting messages from a POP3 server.
-
- @type startedTLS: C{bool}
- @ivar startedTLS: Whether TLS has been negotiated successfully.
-
-
- @type allowInsecureLogin: C{bool}
- @ivar allowInsecureLogin: Indicate whether login() should be
- allowed if the server offers no authentication challenge and if
- our transport does not offer any protection via encryption.
-
- @type serverChallenge: C{str} or C{None}
- @ivar serverChallenge: Challenge received from the server
-
- @type timeout: C{int}
- @ivar timeout: Number of seconds to wait before timing out a
- connection. If the number is <= 0, no timeout checking will be
- performed.
- """
-
- startedTLS = False
- allowInsecureLogin = False
- timeout = 0
- serverChallenge = None
-
- # Capabilities are not allowed to change during the session
- # (except when TLS is negotiated), so cache the first response and
- # use that for all later lookups
- _capCache = None
-
- # Regular expression to search for in the challenge string in the server
- # greeting line.
- _challengeMagicRe = re.compile('(<[^>]+>)')
-
- # List of pending calls.
- # We are a pipelining API but don't actually
- # support pipelining on the network yet.
- _blockedQueue = None
-
- # The Deferred to which the very next result will go.
- _waiting = None
-
- # Whether we dropped the connection because of a timeout
- _timedOut = False
-
- # If the server sends an initial -ERR, this is the message it sent
- # with it.
- _greetingError = None
-
- def _blocked(self, f, *a):
- # Internal helper. If commands are being blocked, append
- # the given command and arguments to a list and return a Deferred
- # that will be chained with the return value of the function
- # when it eventually runs. Otherwise, set up for commands to be
-
- # blocked and return None.
- if self._blockedQueue is not None:
- d = defer.Deferred()
- self._blockedQueue.append((d, f, a))
- return d
- self._blockedQueue = []
- return None
-
- def _unblock(self):
- # Internal helper. Indicate that a function has completed.
- # If there are blocked commands, run the next one. If there
- # are not, set up for the next command to not be blocked.
- if self._blockedQueue == []:
- self._blockedQueue = None
- elif self._blockedQueue is not None:
- _blockedQueue = self._blockedQueue
- self._blockedQueue = None
-
- d, f, a = _blockedQueue.pop(0)
- d2 = f(*a)
- d2.chainDeferred(d)
- # f is a function which uses _blocked (otherwise it wouldn't
- # have gotten into the blocked queue), which means it will have
- # re-set _blockedQueue to an empty list, so we can put the rest
- # of the blocked queue back into it now.
- self._blockedQueue.extend(_blockedQueue)
-
-
- def sendShort(self, cmd, args):
- # Internal helper. Send a command to which a short response
- # is expected. Return a Deferred that fires when the response
- # is received. Block all further commands from being sent until
- # the response is received. Transition the state to SHORT.
- d = self._blocked(self.sendShort, cmd, args)
- if d is not None:
- return d
-
- if args:
- self.sendLine(cmd + ' ' + args)
- else:
- self.sendLine(cmd)
- self.state = 'SHORT'
- self._waiting = defer.Deferred()
- return self._waiting
-
- def sendLong(self, cmd, args, consumer, xform):
- # Internal helper. Send a command to which a multiline
- # response is expected. Return a Deferred that fires when
- # the entire response is received. Block all further commands
- # from being sent until the entire response is received.
- # Transition the state to LONG_INITIAL.
- d = self._blocked(self.sendLong, cmd, args, consumer, xform)
- if d is not None:
- return d
-
- if args:
- self.sendLine(cmd + ' ' + args)
- else:
- self.sendLine(cmd)
- self.state = 'LONG_INITIAL'
- self._xform = xform
- self._consumer = consumer
- self._waiting = defer.Deferred()
- return self._waiting
-
- # Twisted protocol callback
- def connectionMade(self):
- if self.timeout > 0:
- self.setTimeout(self.timeout)
-
- self.state = 'WELCOME'
- self._blockedQueue = []
-
- def timeoutConnection(self):
- self._timedOut = True
- self.transport.loseConnection()
-
- def connectionLost(self, reason):
- if self.timeout > 0:
- self.setTimeout(None)
-
- if self._timedOut:
- reason = error.TimeoutError()
- elif self._greetingError:
- reason = ServerErrorResponse(self._greetingError)
-
- d = []
- if self._waiting is not None:
- d.append(self._waiting)
- self._waiting = None
- if self._blockedQueue is not None:
- d.extend([deferred for (deferred, f, a) in self._blockedQueue])
- self._blockedQueue = None
- for w in d:
- w.errback(reason)
-
- def lineReceived(self, line):
- if self.timeout > 0:
- self.resetTimeout()
-
- state = self.state
- self.state = None
- state = getattr(self, 'state_' + state)(line) or state
- if self.state is None:
- self.state = state
-
- def lineLengthExceeded(self, buffer):
- # XXX - We need to be smarter about this
- if self._waiting is not None:
- waiting, self._waiting = self._waiting, None
- waiting.errback(LineTooLong())
- self.transport.loseConnection()
-
- # POP3 Client state logic - don't touch this.
- def state_WELCOME(self, line):
- # WELCOME is the first state. The server sends one line of text
- # greeting us, possibly with an APOP challenge. Transition the
- # state to WAITING.
- code, status = _codeStatusSplit(line)
- if code != OK:
- self._greetingError = status
- self.transport.loseConnection()
- else:
- m = self._challengeMagicRe.search(status)
-
- if m is not None:
- self.serverChallenge = m.group(1)
-
- self.serverGreeting(status)
-
- self._unblock()
- return 'WAITING'
-
- def state_WAITING(self, line):
- # The server isn't supposed to send us anything in this state.
- log.msg("Illegal line from server: " + repr(line))
-
- def state_SHORT(self, line):
- # This is the state we are in when waiting for a single
- # line response. Parse it and fire the appropriate callback
- # or errback. Transition the state back to WAITING.
- deferred, self._waiting = self._waiting, None
- self._unblock()
- code, status = _codeStatusSplit(line)
- if code == OK:
- deferred.callback(status)
- else:
- deferred.errback(ServerErrorResponse(status))
- return 'WAITING'
-
- def state_LONG_INITIAL(self, line):
- # This is the state we are in when waiting for the first
- # line of a long response. Parse it and transition the
- # state to LONG if it is an okay response; if it is an
- # error response, fire an errback, clean up the things
- # waiting for a long response, and transition the state
- # to WAITING.
- code, status = _codeStatusSplit(line)
- if code == OK:
- return 'LONG'
- consumer = self._consumer
- deferred = self._waiting
- self._consumer = self._waiting = self._xform = None
- self._unblock()
- deferred.errback(ServerErrorResponse(status, consumer))
- return 'WAITING'
-
- def state_LONG(self, line):
- # This is the state for each line of a long response.
- # If it is the last line, finish things, fire the
- # Deferred, and transition the state to WAITING.
- # Otherwise, pass the line to the consumer.
- if line == '.':
- consumer = self._consumer
- deferred = self._waiting
- self._consumer = self._waiting = self._xform = None
- self._unblock()
- deferred.callback(consumer)
- return 'WAITING'
- else:
- if self._xform is not None:
- self._consumer(self._xform(line))
- else:
- self._consumer(line)
- return 'LONG'
-
-
- # Callbacks - override these
- def serverGreeting(self, greeting):
- """Called when the server has sent us a greeting.
-
- @type greeting: C{str} or C{None}
- @param greeting: The status message sent with the server
- greeting. For servers implementing APOP authentication, this
- will be a challenge string. .
- """
-
-
- # External API - call these (most of 'em anyway)
- def startTLS(self, contextFactory=None):
- """
- Initiates a 'STLS' request and negotiates the TLS / SSL
- Handshake.
-
- @type contextFactory: C{ssl.ClientContextFactory} @param
- contextFactory: The context factory with which to negotiate
- TLS. If C{None}, try to create a new one.
-
- @return: A Deferred which fires when the transport has been
- secured according to the given contextFactory, or which fails
- if the transport cannot be secured.
- """
- tls = interfaces.ITLSTransport(self.transport, None)
- if tls is None:
- return defer.fail(TLSError(
- "POP3Client transport does not implement "
- "interfaces.ITLSTransport"))
-
- if contextFactory is None:
- contextFactory = self._getContextFactory()
-
- if contextFactory is None:
- return defer.fail(TLSError(
- "POP3Client requires a TLS context to "
- "initiate the STLS handshake"))
-
- d = self.capabilities()
- d.addCallback(self._startTLS, contextFactory, tls)
- return d
-
-
- def _startTLS(self, caps, contextFactory, tls):
- assert not self.startedTLS, "Client and Server are currently communicating via TLS"
-
- if 'STLS' not in caps:
- return defer.fail(TLSNotSupportedError(
- "Server does not support secure communication "
- "via TLS / SSL"))
-
- d = self.sendShort('STLS', None)
- d.addCallback(self._startedTLS, contextFactory, tls)
- d.addCallback(lambda _: self.capabilities())
- return d
-
-
- def _startedTLS(self, result, context, tls):
- self.transport = tls
- self.transport.startTLS(context)
- self._capCache = None
- self.startedTLS = True
- return result
-
-
- def _getContextFactory(self):
- try:
- from twisted.internet import ssl
- except ImportError:
- return None
- else:
- context = ssl.ClientContextFactory()
- context.method = ssl.SSL.TLSv1_METHOD
- return context
-
-
- def login(self, username, password):
- """Log into the server.
-
- If APOP is available it will be used. Otherwise, if TLS is
- available an 'STLS' session will be started and plaintext
- login will proceed. Otherwise, if the instance attribute
- allowInsecureLogin is set to True, insecure plaintext login
- will proceed. Otherwise, InsecureAuthenticationDisallowed
- will be raised (asynchronously).
-
- @param username: The username with which to log in.
- @param password: The password with which to log in.
-
- @rtype: C{Deferred}
- @return: A deferred which fires when login has
- completed.
- """
- d = self.capabilities()
- d.addCallback(self._login, username, password)
- return d
-
-
- def _login(self, caps, username, password):
- if self.serverChallenge is not None:
- return self._apop(username, password, self.serverChallenge)
-
- tryTLS = 'STLS' in caps
-
- #If our transport supports switching to TLS, we might want to try to switch to TLS.
- tlsableTransport = interfaces.ITLSTransport(self.transport, None) is not None
-
- # If our transport is not already using TLS, we might want to try to switch to TLS.
- nontlsTransport = interfaces.ISSLTransport(self.transport, None) is None
-
- if not self.startedTLS and tryTLS and tlsableTransport and nontlsTransport:
- d = self.startTLS()
-
- d.addCallback(self._loginTLS, username, password)
- return d
-
- elif self.startedTLS or not nontlsTransport or self.allowInsecureLogin:
- return self._plaintext(username, password)
- else:
- return defer.fail(InsecureAuthenticationDisallowed())
-
-
- def _loginTLS(self, res, username, password):
- return self._plaintext(username, password)
-
- def _plaintext(self, username, password):
- # Internal helper. Send a username/password pair, returning a Deferred
- # that fires when both have succeeded or fails when the server rejects
- # either.
- return self.user(username).addCallback(lambda r: self.password(password))
-
- def _apop(self, username, password, challenge):
- # Internal helper. Computes and sends an APOP response. Returns
- # a Deferred that fires when the server responds to the response.
- digest = md5(challenge + password).hexdigest()
- return self.apop(username, digest)
-
- def apop(self, username, digest):
- """Perform APOP login.
-
- This should be used in special circumstances only, when it is
- known that the server supports APOP authentication, and APOP
- authentication is absolutely required. For the common case,
- use L{login} instead.
-
- @param username: The username with which to log in.
- @param digest: The challenge response to authenticate with.
- """
- return self.sendShort('APOP', username + ' ' + digest)
-
- def user(self, username):
- """Send the user command.
-
- This performs the first half of plaintext login. Unless this
- is absolutely required, use the L{login} method instead.
-
- @param username: The username with which to log in.
- """
- return self.sendShort('USER', username)
-
- def password(self, password):
- """Send the password command.
-
- This performs the second half of plaintext login. Unless this
- is absolutely required, use the L{login} method instead.
-
- @param password: The plaintext password with which to authenticate.
- """
- return self.sendShort('PASS', password)
-
- def delete(self, index):
- """Delete a message from the server.
-
- @type index: C{int}
- @param index: The index of the message to delete.
- This is 0-based.
-
- @rtype: C{Deferred}
- @return: A deferred which fires when the delete command
- is successful, or fails if the server returns an error.
- """
- return self.sendShort('DELE', str(index + 1))
-
- def _consumeOrSetItem(self, cmd, args, consumer, xform):
- # Internal helper. Send a long command. If no consumer is
- # provided, create a consumer that puts results into a list
- # and return a Deferred that fires with that list when it
- # is complete.
- if consumer is None:
- L = []
- consumer = _ListSetter(L).setitem
- return self.sendLong(cmd, args, consumer, xform).addCallback(lambda r: L)
- return self.sendLong(cmd, args, consumer, xform)
-
- def _consumeOrAppend(self, cmd, args, consumer, xform):
- # Internal helper. Send a long command. If no consumer is
- # provided, create a consumer that appends results to a list
- # and return a Deferred that fires with that list when it is
- # complete.
- if consumer is None:
- L = []
- consumer = L.append
- return self.sendLong(cmd, args, consumer, xform).addCallback(lambda r: L)
- return self.sendLong(cmd, args, consumer, xform)
-
- def capabilities(self, useCache=True):
- """Retrieve the capabilities supported by this server.
-
- Not all servers support this command. If the server does not
- support this, it is treated as though it returned a successful
- response listing no capabilities. At some future time, this may be
- changed to instead seek out information about a server's
- capabilities in some other fashion (only if it proves useful to do
- so, and only if there are servers still in use which do not support
- CAPA but which do support POP3 extensions that are useful).
-
- @type useCache: C{bool}
- @param useCache: If set, and if capabilities have been
- retrieved previously, just return the previously retrieved
- results.
-
- @return: A Deferred which fires with a C{dict} mapping C{str}
- to C{None} or C{list}s of C{str}. For example::
-
- C: CAPA
- S: +OK Capability list follows
- S: TOP
- S: USER
- S: SASL CRAM-MD5 KERBEROS_V4
- S: RESP-CODES
- S: LOGIN-DELAY 900
- S: PIPELINING
- S: EXPIRE 60
- S: UIDL
- S: IMPLEMENTATION Shlemazle-Plotz-v302
- S: .
-
- will be lead to a result of::
-
- | {'TOP': None,
- | 'USER': None,
- | 'SASL': ['CRAM-MD5', 'KERBEROS_V4'],
- | 'RESP-CODES': None,
- | 'LOGIN-DELAY': ['900'],
- | 'PIPELINING': None,
- | 'EXPIRE': ['60'],
- | 'UIDL': None,
- | 'IMPLEMENTATION': ['Shlemazle-Plotz-v302']}
- """
- if useCache and self._capCache is not None:
- return defer.succeed(self._capCache)
-
- cache = {}
- def consume(line):
- tmp = line.split()
- if len(tmp) == 1:
- cache[tmp[0]] = None
- elif len(tmp) > 1:
- cache[tmp[0]] = tmp[1:]
-
- def capaNotSupported(err):
- err.trap(ServerErrorResponse)
- return None
-
- def gotCapabilities(result):
- self._capCache = cache
- return cache
-
- d = self._consumeOrAppend('CAPA', None, consume, None)
- d.addErrback(capaNotSupported).addCallback(gotCapabilities)
- return d
-
-
- def noop(self):
- """Do nothing, with the help of the server.
-
- No operation is performed. The returned Deferred fires when
- the server responds.
- """
- return self.sendShort("NOOP", None)
-
-
- def reset(self):
- """Remove the deleted flag from any messages which have it.
-
- The returned Deferred fires when the server responds.
- """
- return self.sendShort("RSET", None)
-
-
- def retrieve(self, index, consumer=None, lines=None):
- """Retrieve a message from the server.
-
- If L{consumer} is not None, it will be called with
- each line of the message as it is received. Otherwise,
- the returned Deferred will be fired with a list of all
- the lines when the message has been completely received.
- """
- idx = str(index + 1)
- if lines is None:
- return self._consumeOrAppend('RETR', idx, consumer, _dotUnquoter)
-
- return self._consumeOrAppend('TOP', '%s %d' % (idx, lines), consumer, _dotUnquoter)
-
-
- def stat(self):
- """Get information about the size of this mailbox.
-
- The returned Deferred will be fired with a tuple containing
- the number or messages in the mailbox and the size (in bytes)
- of the mailbox.
- """
- return self.sendShort('STAT', None).addCallback(_statXform)
-
-
- def listSize(self, consumer=None):
- """Retrieve a list of the size of all messages on the server.
-
- If L{consumer} is not None, it will be called with two-tuples
- of message index number and message size as they are received.
- Otherwise, a Deferred which will fire with a list of B{only}
- message sizes will be returned. For messages which have been
- deleted, None will be used in place of the message size.
- """
- return self._consumeOrSetItem('LIST', None, consumer, _listXform)
-
-
- def listUID(self, consumer=None):
- """Retrieve a list of the UIDs of all messages on the server.
-
- If L{consumer} is not None, it will be called with two-tuples
- of message index number and message UID as they are received.
- Otherwise, a Deferred which will fire with of list of B{only}
- message UIDs will be returned. For messages which have been
- deleted, None will be used in place of the message UID.
- """
- return self._consumeOrSetItem('UIDL', None, consumer, _uidXform)
-
-
- def quit(self):
- """Disconnect from the server.
- """
- return self.sendShort('QUIT', None)
-
-__all__ = [
- # Exceptions
- 'InsecureAuthenticationDisallowed', 'LineTooLong', 'POP3ClientError',
- 'ServerErrorResponse', 'TLSError', 'TLSNotSupportedError',
-
- # Protocol classes
- 'POP3Client']