[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - SMTPConfigurations.py:1.1.2.1 SMTPServer.py:1.1.2.2 SMTPServerChannel.py:1.1.2.2 SMTPStatusMessages.py:1.1.2.2
Stephan Richter
srichter@cbu.edu
Mon, 8 Apr 2002 02:51:00 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP
In directory cvs.zope.org:/tmp/cvs-serv31265/SMTP
Modified Files:
Tag: Zope3-Server-Branch
SMTPServer.py SMTPServerChannel.py SMTPStatusMessages.py
Added Files:
Tag: Zope3-Server-Branch
SMTPConfigurations.py
Log Message:
This is the first working version of the SMTP server. There is still a lot
of work to be done, but it is a start. Now I need to stabalize the code and
write some tests.
Also, Gerson Kunze (author of Shicks!), whose code I used as a template,
told me that he would be working on implementing ESMTP and a better SPAM
filter, whcih should make the server even cooler.
I guess we should start discussing how a possible MailService could look
like.
=== Added File Zope3/lib/python/Zope/Server/SMTP/SMTPConfigurations.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: SMTPConfigurations.py,v 1.1.2.1 2002/04/08 06:50:27 srichter Exp $
"""
# ** Relay rules **
# Specify relay level.
# true: Allow relaying except from domains specified in DENY_RELAY_FROM
# and to domains in DENY_RELAY_TO
# false: Deny relaying except from domains specified in ALLOW_RELAY_FROM
# and to domains in ALLOW_RELAY_TO
RELAY_FROM = 1
ACCEPT_RELAY_FROM = ('*cbu.edu', '*zope.org')
DENY_RELAY_FROM = ()
RELAY_TO = 1
ACCEPT_RELAY_TO = ('*.cbu.edu')
DENY_RELAY_TO = ()
# If specified all mail is forwarded to this server.
USE_RELAY_SERVER = ''
# When set to true, a local sender is only allowed to send, if the connection
# is coming from a local IP.
STRICT_RELAY_TEST = 0
# Define some standard mail accounts
ADMIN_ACCOUNT = 'foo'
UNKNOWN_ACCOUNT = 'unknown'
LOCAL_DOMAIN_NAME = '*cbu.edu'
=== Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py 1.1.2.1 => 1.1.2.2 ===
"""
import asyncore
-from FTPServerChannel import FTPServerChannel
+from SMTPServerChannel import SMTPServerChannel
+import SMTPConfigurations
from Zope.Server.ServerBase import ServerBase
-from Zope.Server.Counter import Counter
from Zope.Server.VFS.UnixFileSystem import UnixFileSystem
from Zope.Server.Authentication.DictionaryAuthentication import \
@@ -31,34 +31,26 @@
channel_class = SMTPServerChannel
SERVER_IDENT = 'Zope.Server.SMTPServer'
-
- relay_smtp_server_name = 'mail.cbu.edu'
storage = UnixFileSystem('/opt/ZopeMail')
auth_source = DictionaryAuthentication({'foo': 'bar'})
- refresh_relay_rules = 1
- relay_rules = []
- allow_unknown_receiver_default = 1
- allow_unknown_sender_default = 1
- admin_account = ""
- default_local_domain = ""
- unknown_account = ""
- ip_address_range = None
-
+ config = SMTPConfigurations
- def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1,
- hit_log=None, verbose=0, socket_map=None):
+ def __init__(self, ip, port, maildir, auth, task_dispatcher=None,
+ adj=None, start=1, hit_log=None, verbose=0, socket_map=None):
super(SMTPServer, self).__init__(ip, port, task_dispatcher,
adj, start, hit_log,
verbose, socket_map)
- self.counter = Counter()
+ self.auth_source = auth
+ self.maildir = UnixFileSystem(maildir)
if __name__ == '__main__':
from Zope.Server.TaskThreads import ThreadedTaskDispatcher
td = ThreadedTaskDispatcher()
td.setThreadCount(4)
- SMTPServer('', 8025, task_dispatcher=td)
+ auth_source = DictionaryAuthentication({'foo': 'bar'})
+ SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td)
try:
while 1:
asyncore.poll(5)
=== Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.1 => 1.1.2.2 === (494/594 lines abridged)
"""
-from Zope.Server.ServerChannelBase import ServerChannelBase
-from SMTPimport status_msgs
-from SMTPTask import SMTPTask
+import time
+import fnmatch
+import socket
+
+from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel
+from SMTPStatusMessages import status_msgs
from ISMTPCommandHandler import ISMTPCommandHandler
@@ -30,29 +33,73 @@
__implements__ = ISMTPCommandHandler
# Commands that are run in a separate thread
- thread_commands = ('cmd_mail', 'cmd_vrfy', 'cmd_data')
+ # thread_commands = ('cmd_mail', 'cmd_vrfy', 'cmd_data')
# Define the authentication status of the channel. Note that only the
# "special commands" can be executed without having authenticated.
authenticated = 1
# Define the reply code for an unrecognized command
- unknown_reply = (500, 0)
+ unknown_reply = 'ERR_CMD_UNKNOWN'
# Define the status messages
status_messages = status_msgs
+ # Defines the message terminator (a string sequence that signalizes the
+ # end of a message)
+ message_terminator = '.\r\n'
+
+ # Define the Date/Time format. The Python Mail parser is very strict
+ # about the format of this date.
+ datetime_format = '%a %b %d %H:%M:%S %Y'
+
def __init__(self, server, conn, addr, adj=None, socket_map=None):
super(SMTPServerChannel, self).__init__(server, conn, addr,
adj, socket_map)
+
+ self._from = ''
+ self._to = []
+ self._message = ''
self._sender_host = None
[-=- -=- -=- 494 lines omitted -=- -=- -=-]
+ name = name[1:-1]
+
+ try:
+ username, domain = address.split('@')
+ except:
+ username, domain = address, ''
+
+ return '"%s" <%s@%s>' %(username, username, domain)
+
+
+ def isLocalConnection(self):
+ name = ip2hostname(self.addr[0])
+ match = fnmatch.fnmatch(name, self.server.config.LOCAL_DOMAIN_NAME)
+ return match or name == 'localhost.localdomain'
+
+
+ def isLocalAddress(self, address):
+ # clean up the address
+ if address[0] == '<' or address[-1] == '>':
+ address = address[1:-1]
+
+ # Split the address into it user and domain component
+ try:
+ username, domain = address.split('@')
+ except:
+ username, domain = address, ''
+
+ if ( self.server.auth_source.hasUser(username) and
+ (domain.lower() == self.server.server_name or domain == '') ):
+ return 1
+
+ return 0
+
+
+
+def ip2hostname(ip, default=None):
+ """Resolves an IP into a hostname"""
+ try:
+ return socket.gethostbyaddr(ip)[0]
+ except socket.herror:
+ return default
+
+
+
+def hostname2ip(hostname, default=None):
+ try:
+ return socket.gethostbyname(hostname)
+ except socket.gaierror:
+ return default
+
=== Zope3/lib/python/Zope/Server/SMTP/SMTPStatusMessages.py 1.1.2.1 => 1.1.2.2 ===
status_msgs = {
- 214: ("Help not available. RTFM!",),
- 220: ("Zope Service ready",),
- 221: ("SHICKS! Service closing transmission channel",),
- 250: ('OK',
- '%s', # Username and location
- 'Zope 3.0 ready.', # =
- 'SIZE', # |
- 'VRFY', # |
- 'HELP',), # +--> These are all for HELO
- 251: ("User not local; will forward to <forward-path>",),
- 354: ("Start mail input; end with <CRLF>.<CRLF>",),
- 421: ("Zope Service not available",),
- 450: ("Requested mail action not taken: mailbox unavailable",),
- 500: ('Syntax error, command unrecognized"',),
- 501: ("Syntax error in parameters or arguments",),
- 502: ("Command not implemented",),
- 503: (" Bad sequence of commands",),
- 504: ("Command parameter not implemented",),
- 550: (" Requested action not taken: mailbox unknown",
- 'String does not match anything.'),
- 551: ("ACCESS DENIED.",),
- 554: ("Transaction failed",),
+ 'OK_HELP' : '214 Help not available. RTFM!',
+ 'OK_WELCOME' : '220 %s Zope 3 SMTP Service ready; %s',
+ 'OK_QUIT' : '221 Closing transmission channel',
+ 'OK_NOOP' : '250 OK',
+ 'OK_GREETING' : '250 %s Hello %s [%s], pleased to meet you',
+ 'OK_FROM_ACCPT' : '250 Sender has been accepted',
+ 'OK_TO_ACCPT' : '250 Receiver has been accepted',
+ 'OK_RESET' : '250 Session reset',
+ 'OK_VERIFY' : '250 %s',
+ 'OK_DATA_RECV' : '250 Data received',
+ 'OK_TSFR_START' : '354 Start mail input; end with <CRLF>.<CRLF>',
+
+ 'ERR_CMD_UNKNOWN' : '500 "%s" Syntax error, command unrecognized',
+ 'ERR_DOMAIN_REQ' : '501 HELO requires domain address',
+ 'ERR_MISS_FROM' : '501 MAIL command without "FROM:"',
+ 'ERR_MISS_TO' : '501 RCPT command without "TO:"',
+ 'ERR_USR_UNKNOWN' : '550 No user called "%s" known',
+ 'ERR_FROM_DENIED' : '551 Access for sender %s denied',
+ 'ERR_TO_DENIED' : '551 Access for sender %s denied',
+ 'ERR_ACC_DENIED' : '551 Data transfer access denied',
}
-