[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServer.py:1.1.2.2 FTPServerChannel.py:1.1.2.2

Stephan Richter srichter@cbu.edu
Wed, 3 Apr 2002 00:28:39 -0500


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

Modified Files:
      Tag: Zope3-Server-Branch
	FTPServer.py FTPServerChannel.py 
Log Message:
Got a couple of simple FTP commands working.

Wee, I have no clue how to write tests for this; this seems to be 
non-trivial. I guess I need to have a close look at the HTTP Server 
tests. 


=== Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.1 => 1.1.2.2 ===
 $Id$
 """
-
+import asyncore
 from FTPServerChannel import FTPServerChannel
-from ServerBase import ServerBase
+from Zope.Server.ServerBase import ServerBase
+
+from Zope.Server.VFS.UnixFileSystem import UnixFileSystem 
+from Zope.Server.Authentication.DictionaryAuthentication import \
+     DictionaryAuthentication
 
 
 class FTPServer(ServerBase):
     """Generic FTP Server"""
+
+    filesystem = UnixFileSystem('/')
+    auth_source = DictionaryAuthentication({'foo': 'bar'})
+    
     channel_class = FTPServerChannel
     SERVER_IDENT = 'Zope.Server.FTPServer'
 
 
 if __name__ == '__main__':
-    from TaskThreads import ThreadedTaskDispatcher
+    from Zope.Server.TaskThreads import ThreadedTaskDispatcher
     td = ThreadedTaskDispatcher()
     td.setThreadCount(4)
     FTPServer('', 8021, task_dispatcher=td)


=== Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.1 => 1.1.2.2 ===
 """
 
+from Zope.Server.ServerChannelBase import ServerChannelBase
+from FTPStatusMessages import status_msgs
+from FTPCommandParser import FTPCommandParser
+from FTPTask import FTPTask
+
 from IFTPCommandHandler import IFTPCommandHandler 
-from ServerBase import ServerChannelBase
+from PassiveAcceptor import PassiveAcceptor
 
 
 class FTPServerChannel(ServerChannelBase):
@@ -40,6 +45,25 @@
     passive_mode = 0
 
 
+    system = ('UNIX', 'L8')
+    cwd = '/'
+
+
+    type_map = {
+            'a':'ASCII',
+            'i':'Binary',
+            'e':'EBCDIC',
+            'l':'Binary'
+            }
+    
+    type_mode_map = {
+            'a':'t',
+            'i':'b',
+            'e':'b',
+            'l':'b'
+            }
+
+
     def process_request(self, command):
         """Processes an FTP command.
 
@@ -47,10 +71,14 @@
         """
         assert isinstance(command, FTPCommandParser)
         cmd = command.cmd
-        m = 'do_' + cmd.lower()
-        if hasattr(self, m):
+        m = 'cmd_' + cmd.lower()
+        if m == 'cmd_':            
+            self.reply(500, 0, (''))            
+            self.end_task(0)
+        elif hasattr(self, m):
             # Quick processing
             getattr(self, m)(command.args)
+            self.end_task(0)
         else:
             # Process in another thread.
             task = self.task_class(self, command, m)
@@ -58,15 +86,129 @@
                 self.set_sync()
                 self.server.addTask(task)
             else:
-                # TODO: reply "command unknown"
-                pass
+                self.reply(500, 0, (cmd.upper()))
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Server.FTP.IFTPCommandHandler
+
+    def cmd_abor(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        pass
+
+
+    def cmd_help(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        self.reply(214, flush=0)
+        self.write('Help goes here somewhen.\r\n')
+        self.reply(214, 1)
+
+
+    def cmd_mode(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        if len(args) == 1 and args in 'sS':
+            self.reply(200, 3)
+        else:
+            self.reply(502)
+
+
+    def cmd_noop(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        self.reply(200, 0, ('NOOP'))
+
+
+    def cmd_pasv(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        pc = PassiveAcceptor(self)
+        port = pc.addr[1]
+        ip_addr = pc.control_channel.getsockname()[0]
+        self.reply(227, args=( ','.join('.'.split(ip_addr)),
+                               port/256,
+                               port%256 ) )
+
+
+    def cmd_port(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        info = string.split (args, ',')
+        ip = string.join (info[:4], '.')
+        port = int(info[4])*256 + int(info[5])
+
+        # how many data connections at a time?
+        # I'm assuming one for now...
+        # XXX: we should (optionally) verify that the
+        # ip number belongs to the client.  [wu-ftpd does this?]
+
+        self.client_addr = (ip, port)
+        self.respond (200, args=('PORT',))
+
+
+    def cmd_pwd(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        self.reply(257, 0, self.cwd)
+        
+
+    def cmd_quit(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        self.reply(221)
+        self.close_when_done()
+
+
+    def cmd_syst(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        self.reply(215, 0, self.system)
+        
+
+    def cmd_type(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        # ascii, ebcdic, image, local <byte size>
+        args = args.split()
+        t = args[0].lower()
+        # no support for EBCDIC
+        # if t not in ['a','e','i','l']:
+        if t not in ['a','i','l']:
+            self.reply(500, 0, args=('TYPE',))
+
+        elif t == 'l' and (len(args) > 2 and args[2] != '8'):
+            self.reply(504, 0)
+
+        else:
+            if t == 'a':
+                self.ascii_mode = 1
+            else:
+                self.ascii_mode = 0
+            self.reply(200, 1, self.type_map[t])
+
 
+    def cmd_user(self, args):
+        'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler'
+        if len(args) > 1:
+            self.user_name = args
+            self.reply(331)  # Or whatever the code should be
+        else:
+            self.reply(500, 0, ('USER'))
+
+    #
+    ############################################################
+
+
+    def reply(self, code, pos=0, args=(), flush=1):
+        """ """
+        try:
+            msg = status_msgs[code][pos] %args
+        except:
+            # XXX: Somehow handle the nonexisting response.
+            msg = 'The server created a bad response type (code %i).' %code 
+            code = 500
+
+        if msg.startswith('-'):
+            fill = ''
+        else:
+            fill = ' '
 
-    def do_user(self, args):
-        self.user_name = args
-        self.reply(200)  # Or whatever the code should be
+        self.write('%i%s%s\r\n' %(code, fill, msg))
 
+        if flush:
+            self.flush()
 
-    def do_pass(self, args):
-        self.user_password = args
-        self.reply(200)  # Or whatever the code should be
+        # XXX: Somelogging should go on here.