Ausgabe der neuen DB Einträge

This commit is contained in:
hubobel 2022-01-02 21:50:48 +01:00
parent bad48e1627
commit cfbbb9ee3d
2399 changed files with 843193 additions and 43 deletions

View file

@ -0,0 +1 @@
"Tests for twistd.mail"

View file

@ -0,0 +1,326 @@
#!/usr/bin/env python
# -*- test-case-name: twisted.mail.test.test_pop3client -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from __future__ import print_function
from twisted.internet.protocol import Factory
from twisted.protocols import basic
from twisted.internet import reactor
import sys
USER = "test"
PASS = "twisted"
PORT = 1100
SSL_SUPPORT = True
UIDL_SUPPORT = True
INVALID_SERVER_RESPONSE = False
INVALID_CAPABILITY_RESPONSE = False
INVALID_LOGIN_RESPONSE = False
DENY_CONNECTION = False
DROP_CONNECTION = False
BAD_TLS_RESPONSE = False
TIMEOUT_RESPONSE = False
TIMEOUT_DEFERRED = False
SLOW_GREETING = False
"""Commands"""
CONNECTION_MADE = b"+OK POP3 localhost v2003.83 server ready"
CAPABILITIES = [
b"TOP",
b"LOGIN-DELAY 180",
b"USER",
b"SASL LOGIN"
]
CAPABILITIES_SSL = b"STLS"
CAPABILITIES_UIDL = b"UIDL"
INVALID_RESPONSE = b"-ERR Unknown request"
VALID_RESPONSE = b"+OK Command Completed"
AUTH_DECLINED = b"-ERR LOGIN failed"
AUTH_ACCEPTED = b"+OK Mailbox open, 0 messages"
TLS_ERROR = b"-ERR server side error start TLS handshake"
LOGOUT_COMPLETE = b"+OK quit completed"
NOT_LOGGED_IN = b"-ERR Unknown AUHORIZATION state command"
STAT = b"+OK 0 0"
UIDL = b"+OK Unique-ID listing follows\r\n."
LIST = b"+OK Mailbox scan listing follows\r\n."
CAP_START = b"+OK Capability list follows:"
class POP3TestServer(basic.LineReceiver):
def __init__(self, contextFactory = None):
self.loggedIn = False
self.caps = None
self.tmpUser = None
self.ctx = contextFactory
def sendSTATResp(self, req):
self.sendLine(STAT)
def sendUIDLResp(self, req):
self.sendLine(UIDL)
def sendLISTResp(self, req):
self.sendLine(LIST)
def sendCapabilities(self):
if self.caps is None:
self.caps = [CAP_START]
if UIDL_SUPPORT:
self.caps.append(CAPABILITIES_UIDL)
if SSL_SUPPORT:
self.caps.append(CAPABILITIES_SSL)
for cap in CAPABILITIES:
self.caps.append(cap)
resp = b'\r\n'.join(self.caps)
resp += b'\r\n.'
self.sendLine(resp)
def connectionMade(self):
if DENY_CONNECTION:
self.disconnect()
return
if SLOW_GREETING:
reactor.callLater(20, self.sendGreeting)
else:
self.sendGreeting()
def sendGreeting(self):
self.sendLine(CONNECTION_MADE)
def lineReceived(self, line):
"""Error Conditions"""
uline = line.upper()
find = lambda s: uline.find(s) != -1
if TIMEOUT_RESPONSE:
# Do not respond to clients request
return
if DROP_CONNECTION:
self.disconnect()
return
elif find(b"CAPA"):
if INVALID_CAPABILITY_RESPONSE:
self.sendLine(INVALID_RESPONSE)
else:
self.sendCapabilities()
elif find(b"STLS") and SSL_SUPPORT:
self.startTLS()
elif find(b"USER"):
if INVALID_LOGIN_RESPONSE:
self.sendLine(INVALID_RESPONSE)
return
resp = None
try:
self.tmpUser = line.split(" ")[1]
resp = VALID_RESPONSE
except:
resp = AUTH_DECLINED
self.sendLine(resp)
elif find(b"PASS"):
resp = None
try:
pwd = line.split(" ")[1]
if self.tmpUser is None or pwd is None:
resp = AUTH_DECLINED
elif self.tmpUser == USER and pwd == PASS:
resp = AUTH_ACCEPTED
self.loggedIn = True
else:
resp = AUTH_DECLINED
except:
resp = AUTH_DECLINED
self.sendLine(resp)
elif find(b"QUIT"):
self.loggedIn = False
self.sendLine(LOGOUT_COMPLETE)
self.disconnect()
elif INVALID_SERVER_RESPONSE:
self.sendLine(INVALID_RESPONSE)
elif not self.loggedIn:
self.sendLine(NOT_LOGGED_IN)
elif find(b"NOOP"):
self.sendLine(VALID_RESPONSE)
elif find(b"STAT"):
if TIMEOUT_DEFERRED:
return
self.sendLine(STAT)
elif find(b"LIST"):
if TIMEOUT_DEFERRED:
return
self.sendLine(LIST)
elif find(b"UIDL"):
if TIMEOUT_DEFERRED:
return
elif not UIDL_SUPPORT:
self.sendLine(INVALID_RESPONSE)
return
self.sendLine(UIDL)
def startTLS(self):
if self.ctx is None:
self.getContext()
if SSL_SUPPORT and self.ctx is not None:
self.sendLine(b'+OK Begin TLS negotiation now')
self.transport.startTLS(self.ctx)
else:
self.sendLine(b'-ERR TLS not available')
def disconnect(self):
self.transport.loseConnection()
def getContext(self):
try:
from twisted.internet import ssl
except ImportError:
self.ctx = None
else:
self.ctx = ssl.ClientContextFactory()
self.ctx.method = ssl.SSL.TLSv1_METHOD
usage = """popServer.py [arg] (default is Standard POP Server with no messages)
no_ssl - Start with no SSL support
no_uidl - Start with no UIDL support
bad_resp - Send a non-RFC compliant response to the Client
bad_cap_resp - send a non-RFC compliant response when the Client sends a 'CAPABILITY' request
bad_login_resp - send a non-RFC compliant response when the Client sends a 'LOGIN' request
deny - Deny the connection
drop - Drop the connection after sending the greeting
bad_tls - Send a bad response to a STARTTLS
timeout - Do not return a response to a Client request
to_deferred - Do not return a response on a 'Select' request. This
will test Deferred callback handling
slow - Wait 20 seconds after the connection is made to return a Server Greeting
"""
def printMessage(msg):
print("Server Starting in %s mode" % msg)
def processArg(arg):
if arg.lower() == 'no_ssl':
global SSL_SUPPORT
SSL_SUPPORT = False
printMessage("NON-SSL")
elif arg.lower() == 'no_uidl':
global UIDL_SUPPORT
UIDL_SUPPORT = False
printMessage("NON-UIDL")
elif arg.lower() == 'bad_resp':
global INVALID_SERVER_RESPONSE
INVALID_SERVER_RESPONSE = True
printMessage("Invalid Server Response")
elif arg.lower() == 'bad_cap_resp':
global INVALID_CAPABILITY_RESPONSE
INVALID_CAPABILITY_RESPONSE = True
printMessage("Invalid Capability Response")
elif arg.lower() == 'bad_login_resp':
global INVALID_LOGIN_RESPONSE
INVALID_LOGIN_RESPONSE = True
printMessage("Invalid Capability Response")
elif arg.lower() == 'deny':
global DENY_CONNECTION
DENY_CONNECTION = True
printMessage("Deny Connection")
elif arg.lower() == 'drop':
global DROP_CONNECTION
DROP_CONNECTION = True
printMessage("Drop Connection")
elif arg.lower() == 'bad_tls':
global BAD_TLS_RESPONSE
BAD_TLS_RESPONSE = True
printMessage("Bad TLS Response")
elif arg.lower() == 'timeout':
global TIMEOUT_RESPONSE
TIMEOUT_RESPONSE = True
printMessage("Timeout Response")
elif arg.lower() == 'to_deferred':
global TIMEOUT_DEFERRED
TIMEOUT_DEFERRED = True
printMessage("Timeout Deferred Response")
elif arg.lower() == 'slow':
global SLOW_GREETING
SLOW_GREETING = True
printMessage("Slow Greeting")
elif arg.lower() == '--help':
print(usage)
sys.exit()
else:
print(usage)
sys.exit()
def main():
if len(sys.argv) < 2:
printMessage("POP3 with no messages")
else:
args = sys.argv[1:]
for arg in args:
processArg(arg)
f = Factory()
f.protocol = POP3TestServer
reactor.listenTCP(PORT, f)
reactor.run()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,86 @@
Return-Path: <twisted-commits-admin@twistedmatrix.com>
Delivered-To: exarkun@meson.dyndns.org
Received: from localhost [127.0.0.1]
by localhost with POP3 (fetchmail-6.2.1)
for exarkun@localhost (single-drop); Thu, 20 Mar 2003 14:50:20 -0500 (EST)
Received: from pyramid.twistedmatrix.com (adsl-64-123-27-105.dsl.austtx.swbell.net [64.123.27.105])
by intarweb.us (Postfix) with ESMTP id 4A4A513EA4
for <exarkun@meson.dyndns.org>; Thu, 20 Mar 2003 14:49:27 -0500 (EST)
Received: from localhost ([127.0.0.1] helo=pyramid.twistedmatrix.com)
by pyramid.twistedmatrix.com with esmtp (Exim 3.35 #1 (Debian))
id 18w648-0007Vl-00; Thu, 20 Mar 2003 13:51:04 -0600
Received: from acapnotic by pyramid.twistedmatrix.com with local (Exim 3.35 #1 (Debian))
id 18w63j-0007VK-00
for <twisted-commits@twistedmatrix.com>; Thu, 20 Mar 2003 13:50:39 -0600
To: twisted-commits@twistedmatrix.com
From: etrepum CVS <etrepum@twistedmatrix.com>
Reply-To: twisted-python@twistedmatrix.com
X-Mailer: CVSToys
Message-Id: <E18w63j-0007VK-00@pyramid.twistedmatrix.com>
Subject: [Twisted-commits] rebuild now works on python versions from 2.2.0 and up.
Sender: twisted-commits-admin@twistedmatrix.com
Errors-To: twisted-commits-admin@twistedmatrix.com
X-BeenThere: twisted-commits@twistedmatrix.com
X-Mailman-Version: 2.0.11
Precedence: bulk
List-Help: <mailto:twisted-commits-request@twistedmatrix.com?subject=help>
List-Post: <mailto:twisted-commits@twistedmatrix.com>
List-Subscribe: <http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits>,
<mailto:twisted-commits-request@twistedmatrix.com?subject=subscribe>
List-Id: <twisted-commits.twistedmatrix.com>
List-Unsubscribe: <http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits>,
<mailto:twisted-commits-request@twistedmatrix.com?subject=unsubscribe>
List-Archive: <http://twistedmatrix.com/pipermail/twisted-commits/>
Date: Thu, 20 Mar 2003 13:50:39 -0600
Modified files:
Twisted/twisted/python/rebuild.py 1.19 1.20
Log message:
rebuild now works on python versions from 2.2.0 and up.
ViewCVS links:
http://twistedmatrix.com/users/jh.twistd/viewcvs/cgi/viewcvs.cgi/twisted/python/rebuild.py.diff?r1=text&tr1=1.19&r2=text&tr2=1.20&cvsroot=Twisted
Index: Twisted/twisted/python/rebuild.py
diff -u Twisted/twisted/python/rebuild.py:1.19 Twisted/twisted/python/rebuild.py:1.20
--- Twisted/twisted/python/rebuild.py:1.19 Fri Jan 17 13:50:49 2003
+++ Twisted/twisted/python/rebuild.py Thu Mar 20 11:50:08 2003
@@ -206,15 +206,27 @@
clazz.__dict__.clear()
clazz.__getattr__ = __getattr__
clazz.__module__ = module.__name__
+ if newclasses:
+ import gc
+ if (2, 2, 0) <= sys.version_info[:3] < (2, 2, 2):
+ hasBrokenRebuild = 1
+ gc_objects = gc.get_objects()
+ else:
+ hasBrokenRebuild = 0
for nclass in newclasses:
ga = getattr(module, nclass.__name__)
if ga is nclass:
log.msg("WARNING: new-class %s not replaced by reload!" % reflect.qual(nclass))
else:
- import gc
- for r in gc.get_referrers(nclass):
- if isinstance(r, nclass):
+ if hasBrokenRebuild:
+ for r in gc_objects:
+ if not getattr(r, '__class__', None) is nclass:
+ continue
r.__class__ = ga
+ else:
+ for r in gc.get_referrers(nclass):
+ if getattr(r, '__class__', None) is nclass:
+ r.__class__ = ga
if doLog:
log.msg('')
log.msg(' (fixing %s): ' % str(module.__name__))
_______________________________________________
Twisted-commits mailing list
Twisted-commits@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-commits

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,379 @@
# -*- test-case-name: twisted.mail.test.test_mailmail -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{twisted.mail.scripts.mailmail}, the implementation of the
command line program I{mailmail}.
"""
import os
import sys
from twisted.copyright import version
from twisted.internet.defer import Deferred
from twisted.mail import smtp
from twisted.mail.scripts import mailmail
from twisted.mail.scripts.mailmail import parseOptions
from twisted.python.compat import NativeStringIO
from twisted.python.failure import Failure
from twisted.python.runtime import platformType
from twisted.test.proto_helpers import MemoryReactor
from twisted.trial.unittest import TestCase
class OptionsTests(TestCase):
"""
Tests for L{parseOptions} which parses command line arguments and reads
message text from stdin to produce an L{Options} instance which can be
used to send a message.
"""
memoryReactor = MemoryReactor()
def setUp(self):
"""
Override some things in mailmail, so that we capture C{stdout},
and do not call L{reactor.stop}.
"""
self.out = NativeStringIO()
# Override the mailmail logger, so we capture stderr output
from twisted.logger import textFileLogObserver, Logger
logObserver = textFileLogObserver(self.out)
self.patch(mailmail, '_log', Logger(observer=logObserver))
self.host = None
self.options = None
self.ident = None
# Override mailmail.sendmail, so we don't call reactor.stop()
def sendmail(host, options, ident):
self.host = host
self.options = options
self.ident = ident
return smtp.sendmail(host, options.sender, options.to,
options.body, reactor=self.memoryReactor)
self.patch(mailmail, 'sendmail', sendmail)
def test_unspecifiedRecipients(self):
"""
If no recipients are given in the argument list and there is no
recipient header in the message text, L{parseOptions} raises
L{SystemExit} with a string describing the problem.
"""
self.patch(sys, 'stdin', NativeStringIO(
'Subject: foo\n'
'\n'
'Hello, goodbye.\n'))
exc = self.assertRaises(SystemExit, parseOptions, [])
self.assertEqual(exc.args, ('No recipients specified.',))
def test_listQueueInformation(self):
"""
The I{-bp} option for listing queue information is unsupported and
if it is passed to L{parseOptions}, L{SystemExit} is raised.
"""
exc = self.assertRaises(SystemExit, parseOptions, ['-bp'])
self.assertEqual(exc.args, ("Unsupported option.",))
def test_stdioTransport(self):
"""
The I{-bs} option for using stdin and stdout as the SMTP transport
is unsupported and if it is passed to L{parseOptions}, L{SystemExit}
is raised.
"""
exc = self.assertRaises(SystemExit, parseOptions, ['-bs'])
self.assertEqual(exc.args, ("Unsupported option.",))
def test_ignoreFullStop(self):
"""
The I{-i} and I{-oi} options for ignoring C{"."} by itself on a line
are unsupported and if either is passed to L{parseOptions},
L{SystemExit} is raised.
"""
exc = self.assertRaises(SystemExit, parseOptions, ['-i'])
self.assertEqual(exc.args, ("Unsupported option.",))
exc = self.assertRaises(SystemExit, parseOptions, ['-oi'])
self.assertEqual(exc.args, ("Unsupported option.",))
def test_copyAliasedSender(self):
"""
The I{-om} option for copying the sender if they appear in an alias
expansion is unsupported and if it is passed to L{parseOptions},
L{SystemExit} is raised.
"""
exc = self.assertRaises(SystemExit, parseOptions, ['-om'])
self.assertEqual(exc.args, ("Unsupported option.",))
def test_version(self):
"""
The I{--version} option displays the version and raises
L{SystemExit} with L{None} as the exit code.
"""
out = NativeStringIO()
self.patch(sys, 'stdout', out)
systemExitCode = self.assertRaises(SystemExit, parseOptions,
'--version')
# SystemExit.code is None on success
self.assertEqual(systemExitCode.code, None)
data = out.getvalue()
self.assertEqual(data, "mailmail version: {}\n".format(version))
def test_backgroundDelivery(self):
"""
The I{-odb} flag specifies background delivery.
"""
stdin = NativeStringIO('\n')
self.patch(sys, 'stdin', stdin)
o = parseOptions("-odb")
self.assertTrue(o.background)
def test_foregroundDelivery(self):
"""
The I{-odf} flags specifies foreground delivery.
"""
stdin = NativeStringIO('\n')
self.patch(sys, 'stdin', stdin)
o = parseOptions("-odf")
self.assertFalse(o.background)
def test_recipientsFromHeaders(self):
"""
The I{-t} flags specifies that recipients should be obtained
from headers.
"""
stdin = NativeStringIO(
'To: Curly <invaliduser2@example.com>\n'
'Cc: Larry <invaliduser1@example.com>\n'
'Bcc: Moe <invaliduser3@example.com>\n'
'\n'
'Oh, a wise guy?\n')
self.patch(sys, 'stdin', stdin)
o = parseOptions("-t")
self.assertEqual(len(o.to), 3)
def test_setFrom(self):
"""
When a message has no I{From:} header, a I{From:} value can be
specified with the I{-F} flag.
"""
stdin = NativeStringIO(
'To: invaliduser2@example.com\n'
'Subject: A wise guy?\n\n')
self.patch(sys, 'stdin', stdin)
o = parseOptions(["-F", "Larry <invaliduser1@example.com>", "-t"])
self.assertEqual(o.sender, "Larry <invaliduser1@example.com>")
def test_overrideFromFlagByFromHeader(self):
"""
The I{-F} flag specifies the From: value. However, I{-F} flag is
overriden by the value of From: in the e-mail header.
"""
stdin = NativeStringIO(
'To: Curly <invaliduser4@example.com>\n'
'From: Shemp <invaliduser4@example.com>\n')
self.patch(sys, 'stdin', stdin)
o = parseOptions(["-F", "Groucho <invaliduser5@example.com>", "-t"])
self.assertEqual(o.sender, "invaliduser4@example.com")
def test_runErrorsToStderr(self):
"""
Call L{mailmail.run}, and specify I{-oep} to print errors
to stderr. The sender, to, and printErrors options should be
set and there should be no failure.
"""
argv = ("test_mailmail.py", "invaliduser2@example.com", "-oep")
stdin = NativeStringIO('\n')
self.patch(sys, 'argv', argv)
self.patch(sys, 'stdin', stdin)
mailmail.run()
self.assertEqual(self.options.sender, mailmail.getlogin())
self.assertEqual(self.options.to, ["invaliduser2@example.com"])
# We should have printErrors set because we specified "-oep"
self.assertTrue(self.options.printErrors)
# We should not have any failures.
self.assertIsNone(mailmail.failed)
if platformType == "win32":
test_runErrorsToStderr.skip = (
"mailmail.run() does not work on win32 due to lack of support for"
" getuid()")
def test_readInvalidConfig(self):
"""
Error messages for illegal UID value, illegal GID value, and illegal
identity entry will be sent to stderr.
"""
stdin = NativeStringIO('\n')
self.patch(sys, 'stdin', stdin)
filename = self.mktemp()
myUid = os.getuid()
myGid = os.getgid()
with open(filename, "w") as f:
# Create a config file with some invalid values
f.write("[useraccess]\n"
"allow=invaliduser2,invaliduser1\n"
"deny=invaliduser3,invaliduser4,{}\n"
"order=allow,deny\n"
"[groupaccess]\n"
"allow=invalidgid1,invalidgid2\n"
"deny=invalidgid1,invalidgid2,{}\n"
"order=deny,allow\n"
"[identity]\n"
"localhost=funny\n"
"[addresses]\n"
"smarthost=localhost\n"
"default_domain=example.com\n".format(myUid, myGid))
# The mailmail script looks in
# the twisted.mail.scripts.GLOBAL_CFG variable
# and then the twisted.mail.scripts.LOCAL_CFG
# variable for the path to it's config file.
#
# Override twisted.mail.scripts.LOCAL_CFG with the file we just
# created.
self.patch(mailmail, "LOCAL_CFG", filename)
argv = ("test_mailmail.py", "invaliduser2@example.com", "-oep")
self.patch(sys, 'argv', argv)
mailmail.run()
self.assertRegex(self.out.getvalue(),
"Illegal UID in \\[useraccess\\] section: "
"invaliduser1")
self.assertRegex(self.out.getvalue(),
"Illegal GID in \\[groupaccess\\] section: "
"invalidgid1")
self.assertRegex(self.out.getvalue(),
'Illegal entry in \\[identity\\] section: funny')
if platformType == "win32":
test_readInvalidConfig.skip = ("mailmail.run() does not work on win32"
" due to lack of support for getuid()")
def getConfigFromFile(self, config):
"""
Read a mailmail configuration file.
The mailmail script checks the twisted.mail.scripts.mailmail.GLOBAL_CFG
variable and then the twisted.mail.scripts.mailmail.LOCAL_CFG
variable for the path to its config file.
@param config: path to config file
@type config: L{str}
@return: A parsed config.
@rtype: L{twisted.mail.scripts.mailmail.Configuration}
"""
from twisted.mail.scripts.mailmail import loadConfig
filename = self.mktemp()
with open(filename, "w") as f:
f.write(config)
return loadConfig(filename)
def test_loadConfig(self):
"""
L{twisted.mail.scripts.mailmail.loadConfig}
parses the config file for mailmail.
"""
config = self.getConfigFromFile("""
[addresses]
smarthost=localhost""")
self.assertEqual(config.smarthost, "localhost")
config = self.getConfigFromFile("""
[addresses]
default_domain=example.com""")
self.assertEqual(config.domain, "example.com")
config = self.getConfigFromFile("""
[addresses]
smarthost=localhost
default_domain=example.com""")
self.assertEqual(config.smarthost, "localhost")
self.assertEqual(config.domain, "example.com")
config = self.getConfigFromFile("""
[identity]
host1=invalid
host2=username:password""")
self.assertNotIn("host1", config.identities)
self.assertEqual(config.identities["host2"], ["username", "password"])
config = self.getConfigFromFile("""
[useraccess]
allow=invalid1,35
order=allow""")
self.assertEqual(config.allowUIDs, [35])
config = self.getConfigFromFile("""
[useraccess]
deny=35,36
order=deny""")
self.assertEqual(config.denyUIDs, [35, 36])
config = self.getConfigFromFile("""
[useraccess]
allow=35,36
deny=37,38
order=deny""")
self.assertEqual(config.allowUIDs, [35, 36])
self.assertEqual(config.denyUIDs, [37, 38])
config = self.getConfigFromFile("""
[groupaccess]
allow=gid1,41
order=allow""")
self.assertEqual(config.allowGIDs, [41])
config = self.getConfigFromFile("""
[groupaccess]
deny=41
order=deny""")
self.assertEqual(config.denyGIDs, [41])
config = self.getConfigFromFile("""
[groupaccess]
allow=41,42
deny=43,44
order=allow,deny""")
self.assertEqual(config.allowGIDs, [41, 42])
self.assertEqual(config.denyGIDs, [43, 44])
def test_senderror(self):
"""
L{twisted.mail.scripts.mailmail.senderror} sends mail back to the
sender if an error occurs while sending mail to the recipient.
"""
def sendmail(host, sender, recipient, body):
self.assertRegex(sender, "postmaster@")
self.assertEqual(recipient, ["testsender"])
self.assertRegex(body.getvalue(), "ValueError")
return Deferred()
self.patch(smtp, "sendmail", sendmail)
opts = mailmail.Options()
opts.sender = "testsender"
fail = Failure(ValueError())
mailmail.senderror(fail, opts)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,686 @@
# -*- test-case-name: twisted.mail.test.test_pop3client -*-
# Copyright (c) 2001-2004 Divmod Inc.
# See LICENSE for details.
import sys
import inspect
from zope.interface import directlyProvides
from twisted.internet import reactor, defer, error, protocol, interfaces
from twisted.mail.pop3 import AdvancedPOP3Client as POP3Client
from twisted.mail.pop3 import InsecureAuthenticationDisallowed
from twisted.mail.pop3 import ServerErrorResponse
from twisted.mail.test import pop3testserver
from twisted.protocols import basic, loopback
from twisted.python import log
from twisted.python.compat import intToBytes
from twisted.test.proto_helpers import StringTransport
from twisted.trial import unittest
try:
from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext
except ImportError:
ClientTLSContext = ServerTLSContext = None
class StringTransportWithConnectionLosing(StringTransport):
def loseConnection(self):
self.protocol.connectionLost(error.ConnectionDone())
capCache = {b"TOP": None, b"LOGIN-DELAY": b"180", b"UIDL": None, \
b"STLS": None, b"USER": None, b"SASL": b"LOGIN"}
def setUp(greet=True):
p = POP3Client()
# Skip the CAPA login will issue if it doesn't already have a
# capability cache
p._capCache = capCache
t = StringTransportWithConnectionLosing()
t.protocol = p
p.makeConnection(t)
if greet:
p.dataReceived(b'+OK Hello!\r\n')
return p, t
def strip(f):
return lambda result, f=f: f()
class POP3ClientLoginTests(unittest.TestCase):
def testNegativeGreeting(self):
p, t = setUp(greet=False)
p.allowInsecureLogin = True
d = p.login(b"username", b"password")
p.dataReceived(b'-ERR Offline for maintenance\r\n')
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0],
b"Offline for maintenance"))
def testOkUser(self):
p, t = setUp()
d = p.user(b"username")
self.assertEqual(t.value(), b"USER username\r\n")
p.dataReceived(b"+OK send password\r\n")
return d.addCallback(self.assertEqual, b"send password")
def testBadUser(self):
p, t = setUp()
d = p.user(b"username")
self.assertEqual(t.value(), b"USER username\r\n")
p.dataReceived(b"-ERR account suspended\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"account suspended"))
def testOkPass(self):
p, t = setUp()
d = p.password(b"password")
self.assertEqual(t.value(), b"PASS password\r\n")
p.dataReceived(b"+OK you're in!\r\n")
return d.addCallback(self.assertEqual, b"you're in!")
def testBadPass(self):
p, t = setUp()
d = p.password(b"password")
self.assertEqual(t.value(), b"PASS password\r\n")
p.dataReceived(b"-ERR go away\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"go away"))
def testOkLogin(self):
p, t = setUp()
p.allowInsecureLogin = True
d = p.login(b"username", b"password")
self.assertEqual(t.value(), b"USER username\r\n")
p.dataReceived(b"+OK go ahead\r\n")
self.assertEqual(t.value(), b"USER username\r\nPASS password\r\n")
p.dataReceived(b"+OK password accepted\r\n")
return d.addCallback(self.assertEqual, b"password accepted")
def testBadPasswordLogin(self):
p, t = setUp()
p.allowInsecureLogin = True
d = p.login(b"username", b"password")
self.assertEqual(t.value(), b"USER username\r\n")
p.dataReceived(b"+OK waiting on you\r\n")
self.assertEqual(t.value(), b"USER username\r\nPASS password\r\n")
p.dataReceived(b"-ERR bogus login\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"bogus login"))
def testBadUsernameLogin(self):
p, t = setUp()
p.allowInsecureLogin = True
d = p.login(b"username", b"password")
self.assertEqual(t.value(), b"USER username\r\n")
p.dataReceived(b"-ERR bogus login\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"bogus login"))
def testServerGreeting(self):
p, t = setUp(greet=False)
p.dataReceived(b"+OK lalala this has no challenge\r\n")
self.assertEqual(p.serverChallenge, None)
def testServerGreetingWithChallenge(self):
p, t = setUp(greet=False)
p.dataReceived(b"+OK <here is the challenge>\r\n")
self.assertEqual(p.serverChallenge, b"<here is the challenge>")
def testAPOP(self):
p, t = setUp(greet=False)
p.dataReceived(b"+OK <challenge string goes here>\r\n")
d = p.login(b"username", b"password")
self.assertEqual(t.value(),
b"APOP username f34f1e464d0d7927607753129cabe39a\r\n")
p.dataReceived(b"+OK Welcome!\r\n")
return d.addCallback(self.assertEqual, b"Welcome!")
def testInsecureLoginRaisesException(self):
p, t = setUp(greet=False)
p.dataReceived(b"+OK Howdy\r\n")
d = p.login(b"username", b"password")
self.assertFalse(t.value())
return self.assertFailure(
d, InsecureAuthenticationDisallowed)
def testSSLTransportConsideredSecure(self):
"""
If a server doesn't offer APOP but the transport is secured using
SSL or TLS, a plaintext login should be allowed, not rejected with
an InsecureAuthenticationDisallowed exception.
"""
p, t = setUp(greet=False)
directlyProvides(t, interfaces.ISSLTransport)
p.dataReceived(b"+OK Howdy\r\n")
d = p.login(b"username", b"password")
self.assertEqual(t.value(), b"USER username\r\n")
t.clear()
p.dataReceived(b"+OK\r\n")
self.assertEqual(t.value(), b"PASS password\r\n")
p.dataReceived(b"+OK\r\n")
return d
class ListConsumer:
def __init__(self):
self.data = {}
def consume(self, result):
(item, value) = result
self.data.setdefault(item, []).append(value)
class MessageConsumer:
def __init__(self):
self.data = []
def consume(self, line):
self.data.append(line)
class POP3ClientListTests(unittest.TestCase):
def testListSize(self):
p, t = setUp()
d = p.listSize()
self.assertEqual(t.value(), b"LIST\r\n")
p.dataReceived(b"+OK Here it comes\r\n")
p.dataReceived(b"1 3\r\n2 2\r\n3 1\r\n.\r\n")
return d.addCallback(self.assertEqual, [3, 2, 1])
def testListSizeWithConsumer(self):
p, t = setUp()
c = ListConsumer()
f = c.consume
d = p.listSize(f)
self.assertEqual(t.value(), b"LIST\r\n")
p.dataReceived(b"+OK Here it comes\r\n")
p.dataReceived(b"1 3\r\n2 2\r\n3 1\r\n")
self.assertEqual(c.data, {0: [3], 1: [2], 2: [1]})
p.dataReceived(b"5 3\r\n6 2\r\n7 1\r\n")
self.assertEqual(c.data, {0: [3], 1: [2], 2: [1], 4: [3], 5: [2],
6: [1]})
p.dataReceived(b".\r\n")
return d.addCallback(self.assertIdentical, f)
def testFailedListSize(self):
p, t = setUp()
d = p.listSize()
self.assertEqual(t.value(), b"LIST\r\n")
p.dataReceived(b"-ERR Fatal doom server exploded\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0],
b"Fatal doom server exploded"))
def testListUID(self):
p, t = setUp()
d = p.listUID()
self.assertEqual(t.value(), b"UIDL\r\n")
p.dataReceived(b"+OK Here it comes\r\n")
p.dataReceived(b"1 abc\r\n2 def\r\n3 ghi\r\n.\r\n")
return d.addCallback(self.assertEqual, [b"abc", b"def", b"ghi"])
def testListUIDWithConsumer(self):
p, t = setUp()
c = ListConsumer()
f = c.consume
d = p.listUID(f)
self.assertEqual(t.value(), b"UIDL\r\n")
p.dataReceived(b"+OK Here it comes\r\n")
p.dataReceived(b"1 xyz\r\n2 abc\r\n5 mno\r\n")
self.assertEqual(c.data, {0: [b"xyz"], 1: [b"abc"], 4: [b"mno"]})
p.dataReceived(b".\r\n")
return d.addCallback(self.assertIdentical, f)
def testFailedListUID(self):
p, t = setUp()
d = p.listUID()
self.assertEqual(t.value(), b"UIDL\r\n")
p.dataReceived(b"-ERR Fatal doom server exploded\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0],
b"Fatal doom server exploded"))
class POP3ClientMessageTests(unittest.TestCase):
def testRetrieve(self):
p, t = setUp()
d = p.retrieve(7)
self.assertEqual(t.value(), b"RETR 8\r\n")
p.dataReceived(b"+OK Message incoming\r\n")
p.dataReceived(b"La la la here is message text\r\n")
p.dataReceived(b"..Further message text tra la la\r\n")
p.dataReceived(b".\r\n")
return d.addCallback(
self.assertEqual,
[b"La la la here is message text",
b".Further message text tra la la"])
def testRetrieveWithConsumer(self):
p, t = setUp()
c = MessageConsumer()
f = c.consume
d = p.retrieve(7, f)
self.assertEqual(t.value(), b"RETR 8\r\n")
p.dataReceived(b"+OK Message incoming\r\n")
p.dataReceived(b"La la la here is message text\r\n")
p.dataReceived(b"..Further message text\r\n.\r\n")
return d.addCallback(self._cbTestRetrieveWithConsumer, f, c)
def _cbTestRetrieveWithConsumer(self, result, f, c):
self.assertIdentical(result, f)
self.assertEqual(c.data, [b"La la la here is message text",
b".Further message text"])
def testPartialRetrieve(self):
p, t = setUp()
d = p.retrieve(7, lines=2)
self.assertEqual(t.value(), b"TOP 8 2\r\n")
p.dataReceived(b"+OK 2 lines on the way\r\n")
p.dataReceived(b"Line the first! Woop\r\n")
p.dataReceived(b"Line the last! Bye\r\n")
p.dataReceived(b".\r\n")
return d.addCallback(
self.assertEqual,
[b"Line the first! Woop",
b"Line the last! Bye"])
def testPartialRetrieveWithConsumer(self):
p, t = setUp()
c = MessageConsumer()
f = c.consume
d = p.retrieve(7, f, lines=2)
self.assertEqual(t.value(), b"TOP 8 2\r\n")
p.dataReceived(b"+OK 2 lines on the way\r\n")
p.dataReceived(b"Line the first! Woop\r\n")
p.dataReceived(b"Line the last! Bye\r\n")
p.dataReceived(b".\r\n")
return d.addCallback(self._cbTestPartialRetrieveWithConsumer, f, c)
def _cbTestPartialRetrieveWithConsumer(self, result, f, c):
self.assertIdentical(result, f)
self.assertEqual(c.data, [b"Line the first! Woop",
b"Line the last! Bye"])
def testFailedRetrieve(self):
p, t = setUp()
d = p.retrieve(0)
self.assertEqual(t.value(), b"RETR 1\r\n")
p.dataReceived(b"-ERR Fatal doom server exploded\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0],
b"Fatal doom server exploded"))
def test_concurrentRetrieves(self):
"""
Issue three retrieve calls immediately without waiting for any to
succeed and make sure they all do succeed eventually.
"""
p, t = setUp()
messages = [
p.retrieve(i).addCallback(
self.assertEqual,
[b"First line of " + intToBytes(i + 1) + b".",
b"Second line of " + intToBytes(i + 1) + b"."])
for i
in range(3)]
for i in range(1, 4):
self.assertEqual(t.value(), b"RETR " + intToBytes(i) + b"\r\n")
t.clear()
p.dataReceived(b"+OK 2 lines on the way\r\n")
p.dataReceived(b"First line of " + intToBytes(i) + b".\r\n")
p.dataReceived(b"Second line of " + intToBytes(i) + b".\r\n")
self.assertEqual(t.value(), b"")
p.dataReceived(b".\r\n")
return defer.DeferredList(messages, fireOnOneErrback=True)
class POP3ClientMiscTests(unittest.TestCase):
def testCapability(self):
p, t = setUp()
d = p.capabilities(useCache=0)
self.assertEqual(t.value(), b"CAPA\r\n")
p.dataReceived(b"+OK Capabilities on the way\r\n")
p.dataReceived(b"X\r\nY\r\nZ\r\nA 1 2 3\r\nB 1 2\r\nC 1\r\n.\r\n")
return d.addCallback(
self.assertEqual,
{b"X": None, b"Y": None, b"Z": None,
b"A": [b"1", b"2", b"3"],
b"B": [b"1", b"2"],
b"C": [b"1"]})
def testCapabilityError(self):
p, t = setUp()
d = p.capabilities(useCache=0)
self.assertEqual(t.value(), b"CAPA\r\n")
p.dataReceived(b"-ERR This server is lame!\r\n")
return d.addCallback(self.assertEqual, {})
def testStat(self):
p, t = setUp()
d = p.stat()
self.assertEqual(t.value(), b"STAT\r\n")
p.dataReceived(b"+OK 1 1212\r\n")
return d.addCallback(self.assertEqual, (1, 1212))
def testStatError(self):
p, t = setUp()
d = p.stat()
self.assertEqual(t.value(), b"STAT\r\n")
p.dataReceived(b"-ERR This server is lame!\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"This server is lame!"))
def testNoop(self):
p, t = setUp()
d = p.noop()
self.assertEqual(t.value(), b"NOOP\r\n")
p.dataReceived(b"+OK No-op to you too!\r\n")
return d.addCallback(self.assertEqual, b"No-op to you too!")
def testNoopError(self):
p, t = setUp()
d = p.noop()
self.assertEqual(t.value(), b"NOOP\r\n")
p.dataReceived(b"-ERR This server is lame!\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"This server is lame!"))
def testRset(self):
p, t = setUp()
d = p.reset()
self.assertEqual(t.value(), b"RSET\r\n")
p.dataReceived(b"+OK Reset state\r\n")
return d.addCallback(self.assertEqual, b"Reset state")
def testRsetError(self):
p, t = setUp()
d = p.reset()
self.assertEqual(t.value(), b"RSET\r\n")
p.dataReceived(b"-ERR This server is lame!\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"This server is lame!"))
def testDelete(self):
p, t = setUp()
d = p.delete(3)
self.assertEqual(t.value(), b"DELE 4\r\n")
p.dataReceived(b"+OK Hasta la vista\r\n")
return d.addCallback(self.assertEqual, b"Hasta la vista")
def testDeleteError(self):
p, t = setUp()
d = p.delete(3)
self.assertEqual(t.value(), b"DELE 4\r\n")
p.dataReceived(b"-ERR Winner is not you.\r\n")
return self.assertFailure(
d, ServerErrorResponse).addCallback(
lambda exc: self.assertEqual(exc.args[0], b"Winner is not you."))
class SimpleClient(POP3Client):
def __init__(self, deferred, contextFactory=None):
self.deferred = deferred
self.allowInsecureLogin = True
def serverGreeting(self, challenge):
self.deferred.callback(None)
class POP3HelperMixin:
serverCTX = None
clientCTX = None
def setUp(self):
d = defer.Deferred()
self.server = pop3testserver.POP3TestServer(
contextFactory=self.serverCTX)
self.client = SimpleClient(d, contextFactory=self.clientCTX)
self.client.timeout = 30
self.connected = d
def tearDown(self):
del self.server
del self.client
del self.connected
def _cbStopClient(self, ignore):
self.client.transport.loseConnection()
def _ebGeneral(self, failure):
self.client.transport.loseConnection()
self.server.transport.loseConnection()
return failure
def loopback(self):
return loopback.loopbackTCP(self.server, self.client, noisy=False)
class TLSServerFactory(protocol.ServerFactory):
class protocol(basic.LineReceiver):
context = None
output = []
def connectionMade(self):
self.factory.input = []
self.output = self.output[:]
for line in self.output.pop(0):
self.sendLine(line)
def lineReceived(self, line):
self.factory.input.append(line)
[self.sendLine(l) for l in self.output.pop(0)]
if line == b'STLS':
self.transport.startTLS(self.context)
class POP3TLSTests(unittest.TestCase):
"""
Tests for POP3Client's support for TLS connections.
"""
def test_startTLS(self):
"""
POP3Client.startTLS starts a TLS session over its existing TCP
connection.
"""
sf = TLSServerFactory()
sf.protocol.output = [
[b'+OK'], # Server greeting
[b'+OK', b'STLS', b'.'], # CAPA response
[b'+OK'], # STLS response
[b'+OK', b'.'], # Second CAPA response
[b'+OK'] # QUIT response
]
sf.protocol.context = ServerTLSContext()
port = reactor.listenTCP(0, sf, interface='127.0.0.1')
self.addCleanup(port.stopListening)
H = port.getHost().host
P = port.getHost().port
connLostDeferred = defer.Deferred()
cp = SimpleClient(defer.Deferred(), ClientTLSContext())
def connectionLost(reason):
SimpleClient.connectionLost(cp, reason)
connLostDeferred.callback(None)
cp.connectionLost = connectionLost
cf = protocol.ClientFactory()
cf.protocol = lambda: cp
conn = reactor.connectTCP(H, P, cf)
def cbConnected(ignored):
log.msg("Connected to server; starting TLS")
return cp.startTLS()
def cbStartedTLS(ignored):
log.msg("Started TLS; disconnecting")
return cp.quit()
def cbDisconnected(ign):
log.msg("Disconnected; asserting correct input received")
self.assertEqual(
sf.input,
[b'CAPA', b'STLS', b'CAPA', b'QUIT'])
def cleanup(result):
log.msg("Asserted correct input; disconnecting "
"client and shutting down server")
conn.disconnect()
return connLostDeferred
cp.deferred.addCallback(cbConnected)
cp.deferred.addCallback(cbStartedTLS)
cp.deferred.addCallback(cbDisconnected)
cp.deferred.addBoth(cleanup)
return cp.deferred
class POP3TimeoutTests(POP3HelperMixin, unittest.TestCase):
def testTimeout(self):
def login():
d = self.client.login('test', 'twisted')
d.addCallback(loggedIn)
d.addErrback(timedOut)
return d
def loggedIn(result):
self.fail("Successfully logged in!? Impossible!")
def timedOut(failure):
failure.trap(error.TimeoutError)
self._cbStopClient(None)
def quit():
return self.client.quit()
self.client.timeout = 0.01
# Tell the server to not return a response to client. This
# will trigger a timeout.
pop3testserver.TIMEOUT_RESPONSE = True
methods = [login, quit]
map(self.connected.addCallback, map(strip, methods))
self.connected.addCallback(self._cbStopClient)
self.connected.addErrback(self._ebGeneral)
return self.loopback()
if ClientTLSContext is None:
for case in (POP3TLSTests,):
case.skip = "OpenSSL not present"
elif interfaces.IReactorSSL(reactor, None) is None:
for case in (POP3TLSTests,):
case.skip = "Reactor doesn't support SSL"
import twisted.mail.pop3client
class POP3ClientModuleStructureTests(unittest.TestCase):
"""
Miscellaneous tests more to do with module/package structure than
anything to do with the POP3 client.
"""
def test_all(self):
"""
twisted.mail.pop3client.__all__ should be empty because all classes
should be imported through twisted.mail.pop3.
"""
self.assertEqual(twisted.mail.pop3client.__all__, [])
def test_import(self):
"""
Every public class in twisted.mail.pop3client should be available as a
member of twisted.mail.pop3 with the exception of
twisted.mail.pop3client.POP3Client which should be available as
twisted.mail.pop3.AdvancedClient.
"""
publicClasses = [c[0] for c in inspect.getmembers(
sys.modules['twisted.mail.pop3client'],
inspect.isclass)
if not c[0][0] == '_']
for pc in publicClasses:
if not pc == 'POP3Client':
self.assertTrue(hasattr(twisted.mail.pop3, pc))
else:
self.assertTrue(hasattr(twisted.mail.pop3,
'AdvancedPOP3Client'))

File diff suppressed because it is too large Load diff