[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - SMTPServer.py:1.1.2.3 SMTPServerChannel.py:1.1.2.4

Shane Hathaway shane@cvs.zope.org
Wed, 10 Apr 2002 17:59:23 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP
In directory cvs.zope.org:/tmp/cvs-serv18340/SMTP

Modified Files:
      Tag: Zope3-Server-Branch
	SMTPServer.py SMTPServerChannel.py 
Log Message:
- Removed AlternateSocketMapMixin.  It was there to support multiple socket
maps, but if we really need multiple socket maps, it would be better to
change asyncore.  Had to update a lot of __init__ methods.

- Added IUsernamePassword and IFilesystemAccess, which provide a way to
implement all kinds of authentication schemes without FTP knowing about
any of the details.  Modified FTPServerChannel to work based on an
IFilesystemAccess object.

- Added detection of the ZOPE_SERVER_DEBUG env var.

- Added comments here and there.

- Fixed CRs :-)


=== Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py 1.1.2.2 => 1.1.2.3 ===
-#
-# 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$
-"""
-import asyncore
-from SMTPServerChannel import SMTPServerChannel
-import SMTPConfigurations
-from Zope.Server.ServerBase import ServerBase
-
-from Zope.Server.VFS.UnixFileSystem import UnixFileSystem 
-from Zope.Server.Authentication.DictionaryAuthentication import \
-     DictionaryAuthentication
-
-
-class SMTPServer(ServerBase):
-    """Generic FTP Server"""
-    
-    channel_class = SMTPServerChannel
-    SERVER_IDENT = 'Zope.Server.SMTPServer'
-
-    storage = UnixFileSystem('/opt/ZopeMail')
-    auth_source = DictionaryAuthentication({'foo': 'bar'})
-    config = SMTPConfigurations
-
-    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.auth_source = auth
-        self.maildir = UnixFileSystem(maildir)
-        
-
-if __name__ == '__main__':
-    from Zope.Server.TaskThreads import ThreadedTaskDispatcher
-    td = ThreadedTaskDispatcher()
-    td.setThreadCount(4)
-    auth_source = DictionaryAuthentication({'foo': 'bar'})
-    SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td)
-    try:
-        while 1:
-            asyncore.poll(5)
-            print 'active channels:', SMTPServerChannel.active_channels
-    except KeyboardInterrupt:
-        print 'shutting down...'
-        td.shutdown()
+##############################################################################
+#
+# 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$
+"""
+import asyncore
+from SMTPServerChannel import SMTPServerChannel
+import SMTPConfigurations
+from Zope.Server.ServerBase import ServerBase
+
+from Zope.Server.VFS.UnixFileSystem import UnixFileSystem 
+from Zope.Server.Authentication.DictionaryAuthentication import \
+     DictionaryAuthentication
+
+
+class SMTPServer(ServerBase):
+    """Generic FTP Server"""
+    
+    channel_class = SMTPServerChannel
+    SERVER_IDENT = 'Zope.Server.SMTPServer'
+
+    storage = UnixFileSystem('/opt/ZopeMail')
+    auth_source = DictionaryAuthentication({'foo': 'bar'})
+    config = SMTPConfigurations
+
+    def __init__(self, ip, port, maildir, auth, *args, **kw):
+        
+        self.auth_source = auth
+        self.maildir = UnixFileSystem(maildir)
+        
+        super(SMTPServer, self).__init__(ip, port, *args, **kw)
+
+if __name__ == '__main__':
+    from Zope.Server.TaskThreads import ThreadedTaskDispatcher
+    td = ThreadedTaskDispatcher()
+    td.setThreadCount(4)
+    auth_source = DictionaryAuthentication({'foo': 'bar'})
+    SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td)
+    try:
+        while 1:
+            asyncore.poll(5)
+            print 'active channels:', SMTPServerChannel.active_channels
+    except KeyboardInterrupt:
+        print 'shutting down...'
+        td.shutdown()


=== Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.3 => 1.1.2.4 === (718/818 lines abridged)
-#
-# 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$
-"""
-
-import time
-import fnmatch
-import socket
-
-from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel
-from SMTPStatusMessages import status_msgs
-
-from ISMTPCommandHandler import ISMTPCommandHandler 
-
-
-class SMTPServerChannel(LineServerChannel):
-    """The SMTP Server Channel represents a connection to a particular
-       client. We can therefore store information here."""
-
-    __implements__ = ISMTPCommandHandler
-
-    # Commands that are run in a separate thread
-    # 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 = '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'
-

[-=- -=- -=- 718 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
+