[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - CommonFTPActivityLogger.py:1.1.2.3 FTPCommandParser.py:1.1.2.4 FTPServer.py:1.1.2.5 FTPServerChannel.py:1.1.2.9 FTPStatusMessages.py:1.1.2.5 FTPTask.py:1.1.2.3 FileProducer.py:1.1.2.3 IFTPCommandHandler.py:1.1.2.3 PassiveAcceptor.py:1.1.2.2 PublisherFTPServer.py:1.1.2.2 PublisherFTPTask.py:1.1.2.2 RecvChannel.py:1.1.2.3 XmitChannel.py:1.1.2.2 __init__.py:1.1.2.2

Shane Hathaway shane@cvs.zope.org
Thu, 4 Apr 2002 13:46:28 -0500


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

Modified Files:
      Tag: Zope3-Server-Branch
	CommonFTPActivityLogger.py FTPCommandParser.py FTPServer.py 
	FTPServerChannel.py FTPStatusMessages.py FTPTask.py 
	FileProducer.py IFTPCommandHandler.py PassiveAcceptor.py 
	PublisherFTPServer.py PublisherFTPTask.py RecvChannel.py 
	XmitChannel.py __init__.py 
Log Message:
Just fixed line endings.  No carriage returns.


=== Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.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 time
-import sys
-
-from Zope.Server.Logger.FileLogger import FileLogger
-from Zope.Server.Logger.ResolvingLogger import ResolvingLogger
-from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger
-
-
-class CommonFTPActivityLogger:
-    """Outputs hits in common HTTP log format.
-    """
-
-    def __init__(self, logger_object=None, resolver=None):
-        if logger_object is None:
-            logger_object = FileLogger(sys.stdout)
-
-        if resolver is not None:
-            self.output = ResolvingLogger(resolver, logger_object)
-        else:
-            self.output = UnresolvingLogger(logger_object)
-            
-
-    def log(self, task):
-        """
-        Receives a completed task and logs it in the
-        common log format.
-        """
-
-        now = time.localtime(time.time())
-
-        print now
-        self.output.log('127.0.0.1', time.strftime('%Y/%m/%d %H:%M', now))
+##############################################################################
+#
+# 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 sys
+
+from Zope.Server.Logger.FileLogger import FileLogger
+from Zope.Server.Logger.ResolvingLogger import ResolvingLogger
+from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger
+
+
+class CommonFTPActivityLogger:
+    """Outputs hits in common HTTP log format.
+    """
+
+    def __init__(self, logger_object=None, resolver=None):
+        if logger_object is None:
+            logger_object = FileLogger(sys.stdout)
+
+        if resolver is not None:
+            self.output = ResolvingLogger(resolver, logger_object)
+        else:
+            self.output = UnresolvingLogger(logger_object)
+
+
+    def log(self, task):
+        """
+        Receives a completed task and logs it in the
+        common log format.
+        """
+
+        now = time.localtime(time.time())
+
+        print now
+        self.output.log('127.0.0.1', time.strftime('%Y/%m/%d %H:%M', now))


=== Zope3/lib/python/Zope/Server/FTP/FTPCommandParser.py 1.1.2.3 => 1.1.2.4 ===
-#
-# 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$
-"""
-
-from Zope.Server.IStreamConsumer import IStreamConsumer
-
-
-class FTPCommandParser:
-    """FTP Command parser. Arguments are left alone for now."""
-
-    __implements__ = IStreamConsumer
-
-
-    # See Zope.Server.IStreamConsumer.IStreamConsumer
-    completed = 0
-    inbuf = ''
-    cmd = ''
-    args = ''
-    empty = 0
-
-
-    max_line_length = 1024  # Not a hard limit
-
-
-    def __init__(self, adj):
-        """
-        adj is an Adjustments object.
-        """
-        self.adj = adj
-
-
-    ############################################################
-    # Implementation methods for interface
-    # Zope.Server.IStreamConsumer
-
-    def received(self, data):
-        'See Zope.Server.IStreamConsumer.IStreamConsumer'
-        if self.completed:
-            return 0  # Can't consume any more.
-        pos = data.find('\n')
-        datalen = len(data)
-        if pos < 0:
-            self.inbuf = self.inbuf + data
-            if len(self.inbuf) > self.max_line_length:
-                # Don't accept any more.
-                self.completed = 1
-            return datalen
-        else:
-            # Line finished.
-            s = data[:pos + 1]
-            self.inbuf = self.inbuf + s
-            self.completed = 1
-            line = self.inbuf.strip()
-            self.parseLine(line)
-            return len(s)
-
-    #
-    ############################################################
-
-
-    def parseLine(self, line):
-        parts = line.split(' ', 1)
-        if len(parts) == 2:
-            self.cmd, self.args = parts
-        else:
-            self.cmd = parts[0]
+##############################################################################
+#
+# 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$
+"""
+
+from Zope.Server.IStreamConsumer import IStreamConsumer
+
+
+class FTPCommandParser:
+    """FTP Command parser. Arguments are left alone for now."""
+
+    __implements__ = IStreamConsumer
+
+
+    # See Zope.Server.IStreamConsumer.IStreamConsumer
+    completed = 0
+    inbuf = ''
+    cmd = ''
+    args = ''
+    empty = 0
+
+
+    max_line_length = 1024  # Not a hard limit
+
+
+    def __init__(self, adj):
+        """
+        adj is an Adjustments object.
+        """
+        self.adj = adj
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Server.IStreamConsumer
+
+    def received(self, data):
+        'See Zope.Server.IStreamConsumer.IStreamConsumer'
+        if self.completed:
+            return 0  # Can't consume any more.
+        pos = data.find('\n')
+        datalen = len(data)
+        if pos < 0:
+            self.inbuf = self.inbuf + data
+            if len(self.inbuf) > self.max_line_length:
+                # Don't accept any more.
+                self.completed = 1
+            return datalen
+        else:
+            # Line finished.
+            s = data[:pos + 1]
+            self.inbuf = self.inbuf + s
+            self.completed = 1
+            line = self.inbuf.strip()
+            self.parseLine(line)
+            return len(s)
+
+    #
+    ############################################################
+
+
+    def parseLine(self, line):
+        parts = line.split(' ', 1)
+        if len(parts) == 2:
+            self.cmd, self.args = parts
+        else:
+            self.cmd = parts[0]
+


=== Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.4 => 1.1.2.5 ===
-#
-# 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 FTPServerChannel import FTPServerChannel
-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 \
-     DictionaryAuthentication
-
-
-class FTPServer(ServerBase):
-    """Generic FTP Server"""
-
-    filesystem = UnixFileSystem('/')
-    auth_source = DictionaryAuthentication({'foo': 'bar'})
-    
-    channel_class = FTPServerChannel
-    SERVER_IDENT = 'Zope.Server.FTPServer'
-
-
-    def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1,
-                 hit_log=None, verbose=0, socket_map=None):
-        super(FTPServer, self).__init__(ip, port, task_dispatcher,
-                                        adj, start, hit_log,
-                                        verbose, socket_map)
-
-        # statistics
-        self.total_sessions = Counter()
-        self.closed_sessions = Counter()
-        self.total_files_out = Counter()
-        self.total_files_in = Counter()
-        self.total_bytes_out = Counter()
-        self.total_bytes_in = Counter()
-        self.total_exceptions = Counter()
-
-
-if __name__ == '__main__':
-    from Zope.Server.TaskThreads import ThreadedTaskDispatcher
-    td = ThreadedTaskDispatcher()
-    td.setThreadCount(4)
-    FTPServer('', 8021, task_dispatcher=td)
-    try:
-        while 1:
-            asyncore.poll(5)
-            print 'active channels:', FTPServerChannel.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 FTPServerChannel import FTPServerChannel
+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 \
+     DictionaryAuthentication
+
+
+class FTPServer(ServerBase):
+    """Generic FTP Server"""
+
+    filesystem = UnixFileSystem('/')
+    auth_source = DictionaryAuthentication({'foo': 'bar'})
+
+    channel_class = FTPServerChannel
+    SERVER_IDENT = 'Zope.Server.FTPServer'
+
+
+    def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1,
+                 hit_log=None, verbose=0, socket_map=None):
+        super(FTPServer, self).__init__(ip, port, task_dispatcher,
+                                        adj, start, hit_log,
+                                        verbose, socket_map)
+
+        # statistics
+        self.total_sessions = Counter()
+        self.closed_sessions = Counter()
+        self.total_files_out = Counter()
+        self.total_files_in = Counter()
+        self.total_bytes_out = Counter()
+        self.total_bytes_in = Counter()
+        self.total_exceptions = Counter()
+
+
+if __name__ == '__main__':
+    from Zope.Server.TaskThreads import ThreadedTaskDispatcher
+    td = ThreadedTaskDispatcher()
+    td.setThreadCount(4)
+    FTPServer('', 8021, task_dispatcher=td)
+    try:
+        while 1:
+            asyncore.poll(5)
+            print 'active channels:', FTPServerChannel.active_channels
+    except KeyboardInterrupt:
+        print 'shutting down...'
+        td.shutdown()


=== Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.8 => 1.1.2.9 === (1103/1203 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 os
-import stat
-import socket
-import time
-
-from Zope.Server.ServerChannelBase import ServerChannelBase
-from FTPStatusMessages import status_msgs
-from FTPCommandParser import FTPCommandParser
-from FTPTask import FTPTask
-from FileProducer import FileProducer
-
-from IFTPCommandHandler import IFTPCommandHandler 
-from PassiveAcceptor import PassiveAcceptor
-from RecvChannel import RecvChannel
-from XmitChannel import XmitChannel
-
-
-# These are the commands that are accessing the filesystem.
-# Since this could be also potentially a longer process, these commands
-# are slao the ones that are executed in a different thread.
-fs_access_cmds = ('cmd_appe', 'cmd_cdup', 'cmd_cwd', 'cmd_dele', 'cmd_list',
-                  'cmd_nlst', 'cmd_mdtm', 'cmd_mkd', 'cmd_pass', 'cmd_retr',
-                  'cmd_rmd', 'cmd_rnfr', 'cmd_rnto', 'cmd_size', 'cmd_stor',
-                  'cmd_stru')
-
-
-class FTPServerChannel(ServerChannelBase):
-    """The FTP Server Channel represents a connection to a particular
-       client. We can therefore store information here."""
-
-    __implements__ = IFTPCommandHandler
-
-    task_class = FTPTask

[-=- -=- -=- 1103 lines omitted -=- -=- -=-]

+
+    # pretty much the same as xmit, but only right on the verge of
+    # being worth a merge.
+    def createRecvChannel(self, fd):
+        pa = self.passive_acceptor
+        if pa:
+            if pa.ready:
+                # a connection has already been made.
+                conn, addr = pa.ready
+                cdc = RecvChannel(self, addr, fd)
+                cdc.set_socket (conn)
+                cdc.connected = 1
+                self.passive_acceptor.close()
+                self.passive_acceptor = None
+            else:
+                # we're still waiting for a connect to the PASV port.
+                cdc = RecvChannel(self, None, fd)
+        else:
+            # not in PASV mode.
+            ip, port = self.client_addr
+            cdc = RecvChannel(self, self.client_addr, fd)
+            cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+            try:
+                cdc.connect ((ip, port))
+            except socket.error, why:
+                self.reply(425)
+
+        self.client_dc = cdc
+
+
+    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 = ' '
+
+        self.write('%i%s%s\r\n' %(code, fill, msg))
+
+        if flush:
+            self.flush()
+
+        # XXX: Some logging should go on here.


=== Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.py 1.1.2.4 => 1.1.2.5 ===
-#
-# 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$
-"""
-
-
-status_msgs = {
-    150: ('Opening %s mode data connection for file list',
-          'Opening %s connection for %s',),
-    200: ('%s command successful.',
-          'Type set to %s.',
-          'STRU F Ok.',
-          'MODE S Ok.',),
-    213: ('%4d%02d%02d%02d%02d%02d', # A date
-          '%d Bytes'), # Size
-    214: ('-The following commands are recognized',
-          ''),
-    215: ('%s Type: %s',),  # Server Type
-    220: ('%s FTP server (Zope Async/Thread V0.1) ready.',),
-    221: ('Goodbye.',),
-    226: ('%s command successful.',
-          'Transfer successful.'),
-    227: ('Entering Passive Mode (%s,%d,%d)',),
-    230: ('Login Successful.',),
-    250: ('%s command successful.',),
-    257: ('%s command successful.',
-          "'%s' is the current directory.",),
-    331: ('Password required',),
-    350: ('Restarting at %d. Send STORE or RETRIEVE to initiate transfer.',
-          'File exists, ready for destination.',),
-    425: ("Can't build data connection",),
-    426: ('Connection closed; transfer aborted.',),
-    500: ("'%s': command not understood.",),
-    502: ("Unimplemented MODE type",),
-    504: ('Byte size must be 8',
-          'Unimplemented STRU type',),
-    530: ("You are not authorized to perform the '%s' command",
-          'Please log in with USER and PASS',
-          'The username and password do not match.',),
-    550: ('Could not list directory: %s',
-          '%s: No such directory.',
-          '%s: No such file.',
-          '%s: Is not a file',
-          'Error creating file.',
-          'Error creating directory.',
-          'Error deleting file.',
-          'Error removing directory.'),
-    553: ('Could not open file for reading: %s',
-          'Could not open file for writing: %s',
-          'Restart on STOR not yet supported',),
-
-    560: ('Could not rename %s to %s.',
-          'No source filename specify. Call RNFR first.',),
-    }
-
+##############################################################################
+#
+# 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$
+"""
+
+
+status_msgs = {
+    150: ('Opening %s mode data connection for file list',
+          'Opening %s connection for %s',),
+    200: ('%s command successful.',
+          'Type set to %s.',
+          'STRU F Ok.',
+          'MODE S Ok.',),
+    213: ('%4d%02d%02d%02d%02d%02d', # A date
+          '%d Bytes'), # Size
+    214: ('-The following commands are recognized',
+          ''),
+    215: ('%s Type: %s',),  # Server Type
+    220: ('%s FTP server (Zope Async/Thread V0.1) ready.',),
+    221: ('Goodbye.',),
+    226: ('%s command successful.',
+          'Transfer successful.'),
+    227: ('Entering Passive Mode (%s,%d,%d)',),
+    230: ('Login Successful.',),
+    250: ('%s command successful.',),
+    257: ('%s command successful.',
+          "'%s' is the current directory.",),
+    331: ('Password required',),
+    350: ('Restarting at %d. Send STORE or RETRIEVE to initiate transfer.',
+          'File exists, ready for destination.',),
+    425: ("Can't build data connection",),
+    426: ('Connection closed; transfer aborted.',),
+    500: ("'%s': command not understood.",),
+    502: ("Unimplemented MODE type",),
+    504: ('Byte size must be 8',
+          'Unimplemented STRU type',),
+    530: ("You are not authorized to perform the '%s' command",
+          'Please log in with USER and PASS',
+          'The username and password do not match.',),
+    550: ('Could not list directory: %s',
+          '%s: No such directory.',
+          '%s: No such file.',
+          '%s: Is not a file',
+          'Error creating file.',
+          'Error creating directory.',
+          'Error deleting file.',
+          'Error removing directory.'),
+    553: ('Could not open file for reading: %s',
+          'Could not open file for writing: %s',
+          'Restart on STOR not yet supported',),
+
+    560: ('Could not rename %s to %s.',
+          'No source filename specify. Call RNFR first.',),
+    }
+


=== Zope3/lib/python/Zope/Server/FTP/FTPTask.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 socket
-import time
-from Zope.Server.ITask import ITask
-
-
-class FTPTask:
-    """
-    """
-
-    __implements__ = ITask
-
-
-    def __init__(self, channel, command, m_name):
-        self.channel = channel
-        self.m_name = m_name
-        self.args = command.args
-
-        self.close_on_finish = 0
-
-
-    ############################################################
-    # Implementation methods for interface
-    # Zope.Server.ITask
-
-    def service(self):
-        """Called to execute the task.
-        """
-        try:
-            try:
-                self.start()
-                getattr(self.channel, self.m_name)(self.args)
-                self.finish()
-            except socket.error:
-                self.close_on_finish = 1
-                if self.channel.adj.log_socket_errors:
-                    raise
-        finally:
-            self.channel.end_task(self.close_on_finish)
-
-
-    def cancel(self):
-        'See Zope.Server.ITask.ITask'
-        self.channel.close_when_done()
-
-
-    def defer(self):
-        'See Zope.Server.ITask.ITask'
-        pass
-
-    #
-    ############################################################
-
-    def start(self):
-        now = time.time()
-        self.start_time = now
-
-
-    def finish(self):
-        hit_log = self.channel.server.hit_log
-        if hit_log is not None:
-            hit_log.log(self)
+##############################################################################
+#
+# 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 socket
+import time
+from Zope.Server.ITask import ITask
+
+
+class FTPTask:
+    """
+    """
+
+    __implements__ = ITask
+
+
+    def __init__(self, channel, command, m_name):
+        self.channel = channel
+        self.m_name = m_name
+        self.args = command.args
+
+        self.close_on_finish = 0
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Server.ITask
+
+    def service(self):
+        """Called to execute the task.
+        """
+        try:
+            try:
+                self.start()
+                getattr(self.channel, self.m_name)(self.args)
+                self.finish()
+            except socket.error:
+                self.close_on_finish = 1
+                if self.channel.adj.log_socket_errors:
+                    raise
+        finally:
+            self.channel.end_task(self.close_on_finish)
+
+
+    def cancel(self):
+        'See Zope.Server.ITask.ITask'
+        self.channel.close_when_done()
+
+
+    def defer(self):
+        'See Zope.Server.ITask.ITask'
+        pass
+
+    #
+    ############################################################
+
+    def start(self):
+        now = time.time()
+        self.start_time = now
+
+
+    def finish(self):
+        hit_log = self.channel.server.hit_log
+        if hit_log is not None:
+            hit_log.log(self)


=== Zope3/lib/python/Zope/Server/FTP/FileProducer.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$
-"""
-
-class FileProducer:
-    """ """
-    block_size = 16384
-
-    def __init__(self, server, dc, fd):
-        self.fd = fd
-        self.done = 0
-
-        
-    def more(self):
-        if self.done:
-            return ''
-        else:
-            block = self.fd.read(self.block_size)
-            if not block:
-                self.fd.close()
-                self.done = 1
-            return block
+##############################################################################
+#
+# 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$
+"""
+
+class FileProducer:
+    """ """
+    block_size = 16384
+
+    def __init__(self, server, dc, fd):
+        self.fd = fd
+        self.done = 0
+
+
+    def more(self):
+        if self.done:
+            return ''
+        else:
+            block = self.fd.read(self.block_size)
+            if not block:
+                self.fd.close()
+                self.done = 1
+            return block


=== Zope3/lib/python/Zope/Server/FTP/IFTPCommandHandler.py 1.1.2.2 => 1.1.2.3 ===
-
-from Interface import Interface
-
-class IFTPCommandHandler(Interface):
-    """This interface defines all the FTP commands that are supported by the
-       server.
-
-       Every command takes the command line as first arguments, since it is
-       responsible 
-    """
-
-    def cmd_abor(args):
-        """Abort operation. No read access required.
-        """
-
-    def cmd_appe(args):
-        """Append to a file. Write access required.
-        """
-
-    def cmd_cdup(args):
-        """Change to parent of current working directory.
-        """
-
-    def cmd_cwd(args):
-        """Change working directory.
-        """
-
-    def cmd_dele(args):
-        """Delete a file. Write access required.
-        """
-        
-    def cmd_help(args):
-        """Give help information. No read access required.
-        """
-
-    def cmd_list(args):
-        """Give list files in a directory.
-        """
-
-    def cmd_mdtm(args):
-        """Show last modification time of file.
-
-           Example output: 213 19960301204320
-        """
-
-    def cmd_mkd(args):
-        """Make a directory. Write access required.
-        """
-
-    def cmd_mode(args):
-        """Set file transfer mode.  No read access required. Obselete.
-        """
-
-    def cmd_nlst(args):
-        """Give name list of files in directory.
-        """
-
-    def cmd_noop(args):
-        """Do nothing. No read access required.
-        """
-
-    def cmd_pass(args):
-        """Specify password.
-        """
-
-    def cmd_pasv(args):
-        """Prepare for server-to-server transfer. No read access required.
-        """
-
-    def cmd_port(args):
-        """Specify data connection port. No read access required.
-        """
-
-    def cmd_pwd(args):
-        """Print the current working directory.
-        """
-
-    def cmd_quit(args):
-        """Terminate session. No read access required.
-        """
-
-    def cmd_rest(args):
-        """Restart incomplete transfer.
-        """
-
-    def cmd_retr(args):
-        """Retrieve a file.
-        """
-
-    def cmd_rmd(args):
-        """Remove a directory. Write access required.
-        """
-
-    def cmd_rnfr(args):
-        """Specify rename-from file name. Write access required.
-        """
-
-    def cmd_rnto(args):
-        """Specify rename-to file name. Write access required.
-        """
-
-    def cmd_size(args):
-        """Return size of file.
-        """
-
-    def cmd_stat(args):
-        """Return status of server. No read access required.
-        """
-        
-    def cmd_stor(args):
-        """Store a file. Write access required.
-        """
-
-    def cmd_stru(args):
-        """Set file transfer structure. Obselete."""
-
-    def cmd_syst(args):
-        """Show operating system type of server system.
-
-           No read access required.
-
-           Replying to this command is of questionable utility,
-           because this server does not behave in a predictable way
-           w.r.t. the output of the LIST command.  We emulate Unix ls
-           output, but on win32 the pathname can contain drive
-           information at the front Currently, the combination of
-           ensuring that os.sep == '/' and removing the leading slash
-           when necessary seems to work.  [cd'ing to another drive
-           also works]
-        
-           This is how wuftpd responds, and is probably the most
-           expected.  The main purpose of this reply is so that the
-           client knows to expect Unix ls-style LIST output.
-        
-           one disadvantage to this is that some client programs
-           assume they can pass args to /bin/ls.  a few typical
-           responses:
-           
-           215 UNIX Type: L8 (wuftpd)
-           215 Windows_NT version 3.51
-           215 VMS MultiNet V3.3
-           500 'SYST': command not understood. (SVR4)
-        """
-
-    def cmd_type(args):
-        """Specify data transfer type. No read access required.
-        """
-
-    def cmd_user(args):
-        """Specify user name. No read access required.
-        """
-
-
-
-# this is the command list from the wuftpd man page
-# '!' requires write access
-#
-not_implemented_commands = {
-        'acct':	'specify account (ignored)',
-        'allo':	'allocate storage (vacuously)',
-        'site':	'non-standard commands (see next section)',
-        'stou':	'store a file with a unique name',	                    #!
-        'xcup':	'change to parent of current working directory (deprecated)',
-        'xcwd':	'change working directory (deprecated)',
-        'xmkd':	'make a directory (deprecated)',	                    #!
-        'xpwd':	'print the current working directory (deprecated)',
-        'xrmd':	'remove a directory (deprecated)',	                    #!
-}
+
+
+from Interface import Interface
+
+class IFTPCommandHandler(Interface):
+    """This interface defines all the FTP commands that are supported by the
+       server.
+
+       Every command takes the command line as first arguments, since it is
+       responsible
+    """
+
+    def cmd_abor(args):
+        """Abort operation. No read access required.
+        """
+
+    def cmd_appe(args):
+        """Append to a file. Write access required.
+        """
+
+    def cmd_cdup(args):
+        """Change to parent of current working directory.
+        """
+
+    def cmd_cwd(args):
+        """Change working directory.
+        """
+
+    def cmd_dele(args):
+        """Delete a file. Write access required.
+        """
+
+    def cmd_help(args):
+        """Give help information. No read access required.
+        """
+
+    def cmd_list(args):
+        """Give list files in a directory.
+        """
+
+    def cmd_mdtm(args):
+        """Show last modification time of file.
+
+           Example output: 213 19960301204320
+        """
+
+    def cmd_mkd(args):
+        """Make a directory. Write access required.
+        """
+
+    def cmd_mode(args):
+        """Set file transfer mode.  No read access required. Obselete.
+        """
+
+    def cmd_nlst(args):
+        """Give name list of files in directory.
+        """
+
+    def cmd_noop(args):
+        """Do nothing. No read access required.
+        """
+
+    def cmd_pass(args):
+        """Specify password.
+        """
+
+    def cmd_pasv(args):
+        """Prepare for server-to-server transfer. No read access required.
+        """
+
+    def cmd_port(args):
+        """Specify data connection port. No read access required.
+        """
+
+    def cmd_pwd(args):
+        """Print the current working directory.
+        """
+
+    def cmd_quit(args):
+        """Terminate session. No read access required.
+        """
+
+    def cmd_rest(args):
+        """Restart incomplete transfer.
+        """
+
+    def cmd_retr(args):
+        """Retrieve a file.
+        """
+
+    def cmd_rmd(args):
+        """Remove a directory. Write access required.
+        """
+
+    def cmd_rnfr(args):
+        """Specify rename-from file name. Write access required.
+        """
+
+    def cmd_rnto(args):
+        """Specify rename-to file name. Write access required.
+        """
+
+    def cmd_size(args):
+        """Return size of file.
+        """
+
+    def cmd_stat(args):
+        """Return status of server. No read access required.
+        """
+
+    def cmd_stor(args):
+        """Store a file. Write access required.
+        """
+
+    def cmd_stru(args):
+        """Set file transfer structure. Obselete."""
+
+    def cmd_syst(args):
+        """Show operating system type of server system.
+
+           No read access required.
+
+           Replying to this command is of questionable utility,
+           because this server does not behave in a predictable way
+           w.r.t. the output of the LIST command.  We emulate Unix ls
+           output, but on win32 the pathname can contain drive
+           information at the front Currently, the combination of
+           ensuring that os.sep == '/' and removing the leading slash
+           when necessary seems to work.  [cd'ing to another drive
+           also works]
+
+           This is how wuftpd responds, and is probably the most
+           expected.  The main purpose of this reply is so that the
+           client knows to expect Unix ls-style LIST output.
+
+           one disadvantage to this is that some client programs
+           assume they can pass args to /bin/ls.  a few typical
+           responses:
+
+           215 UNIX Type: L8 (wuftpd)
+           215 Windows_NT version 3.51
+           215 VMS MultiNet V3.3
+           500 'SYST': command not understood. (SVR4)
+        """
+
+    def cmd_type(args):
+        """Specify data transfer type. No read access required.
+        """
+
+    def cmd_user(args):
+        """Specify user name. No read access required.
+        """
+
+
+
+# this is the command list from the wuftpd man page
+# '!' requires write access
+#
+not_implemented_commands = {
+        'acct':        'specify account (ignored)',
+        'allo':        'allocate storage (vacuously)',
+        'site':        'non-standard commands (see next section)',
+        'stou':        'store a file with a unique name',                            #!
+        'xcup':        'change to parent of current working directory (deprecated)',
+        'xcwd':        'change working directory (deprecated)',
+        'xmkd':        'make a directory (deprecated)',                            #!
+        'xpwd':        'print the current working directory (deprecated)',
+        'xrmd':        'remove a directory (deprecated)',                            #!
+}


=== Zope3/lib/python/Zope/Server/FTP/PassiveAcceptor.py 1.1.2.1 => 1.1.2.2 ===
-#
-# 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
-import socket
-
-        
-class PassiveAcceptor(asyncore.dispatcher):
-    """This socket accepts a data connection, used when the server has
-       been placed in passive mode.  Although the RFC implies that we
-       ought to be able to use the same acceptor over and over again,
-       this presents a problem: how do we shut it off, so that we are
-       accepting connections only when we expect them?  [we can't]
-
-       wuftpd, and probably all the other servers, solve this by
-       allowing only one connection to hit this acceptor.  They then
-       close it.  Any subsequent data-connection command will then try
-       for the default port on the client side [which is of course
-       never there].  So the 'always-send-PORT/PASV' behavior seems
-       required.
-
-       Another note: wuftpd will also be listening on the channel as
-       soon as the PASV command is sent.  It does not wait for a data
-       command first.
-
-       --- we need to queue up a particular behavior:
-       1) xmit : queue up producer[s]
-       2) recv : the file object
-
-       It would be nice if we could make both channels the same.
-       Hmmm.."""
-
-    __implements__ = asyncore.dispatcher.__implements__
-
-    ready = None
-    
-    def __init__ (self, control_channel):
-        asyncore.dispatcher.__init__ (self)
-        self.control_channel = control_channel
-        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
-        # bind to an address on the interface that the
-        # control connection is coming from.
-        self.bind ( (self.control_channel.getsockname()[0], 0) )
-        self.addr = self.getsockname()
-        self.listen(1)
-        
-
-    def log (self, *ignore):
-        pass
-
-        
-    def handle_accept (self):
-        conn, addr = self.accept()
-        dc = self.control_channel.client_dc
-        if dc is not None:
-            dc.set_socket(conn)
-            dc.addr = addr
-            dc.connected = 1
-            self.control_channel.passive_acceptor = None
-        else:
-            self.ready = conn, addr
-        self.close()
+##############################################################################
+#
+# 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
+import socket
+
+
+class PassiveAcceptor(asyncore.dispatcher):
+    """This socket accepts a data connection, used when the server has
+       been placed in passive mode.  Although the RFC implies that we
+       ought to be able to use the same acceptor over and over again,
+       this presents a problem: how do we shut it off, so that we are
+       accepting connections only when we expect them?  [we can't]
+
+       wuftpd, and probably all the other servers, solve this by
+       allowing only one connection to hit this acceptor.  They then
+       close it.  Any subsequent data-connection command will then try
+       for the default port on the client side [which is of course
+       never there].  So the 'always-send-PORT/PASV' behavior seems
+       required.
+
+       Another note: wuftpd will also be listening on the channel as
+       soon as the PASV command is sent.  It does not wait for a data
+       command first.
+
+       --- we need to queue up a particular behavior:
+       1) xmit : queue up producer[s]
+       2) recv : the file object
+
+       It would be nice if we could make both channels the same.
+       Hmmm.."""
+
+    __implements__ = asyncore.dispatcher.__implements__
+
+    ready = None
+
+    def __init__ (self, control_channel):
+        asyncore.dispatcher.__init__ (self)
+        self.control_channel = control_channel
+        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        # bind to an address on the interface that the
+        # control connection is coming from.
+        self.bind ( (self.control_channel.getsockname()[0], 0) )
+        self.addr = self.getsockname()
+        self.listen(1)
+
+
+    def log (self, *ignore):
+        pass
+
+
+    def handle_accept (self):
+        conn, addr = self.accept()
+        dc = self.control_channel.client_dc
+        if dc is not None:
+            dc.set_socket(conn)
+            dc.addr = addr
+            dc.connected = 1
+            self.control_channel.passive_acceptor = None
+        else:
+            self.ready = conn, addr
+        self.close()


=== Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.1 => 1.1.2.2 ===
 # 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.
-# 
+#
 ##############################################################################
 """
 


=== Zope3/lib/python/Zope/Server/FTP/PublisherFTPTask.py 1.1.2.1 => 1.1.2.2 ===
-#
-# 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$
-"""
-
-from FTPTask import FTPTask
-from Zope.Publisher.Publish import publish
-
-
-class PublisherFTPTask(FTPTask):
-    """ """
-
-    __implements__ = FTPTask.__implements__
-    
-
-    def execute(self):
-        """ """
-        server = self.channel.server
-        env = self.create_environment()
-        instream = self.request_data.getBodyStream()
-
-        request = server.request_factory(instream, self, env)
-        publish(request)
-
-
-    def create_environment(self):
-        request_data = self.request_data
-        channel = self.channel
-        server = channel.server
-
-        # This should probably change to reflect calling the FileSystem
-        # methods
-        env = {'command': request_data.command
-               'args': request_data.args
-               }
-
-
-        return env
+##############################################################################
+#
+# 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$
+"""
+
+from FTPTask import FTPTask
+from Zope.Publisher.Publish import publish
+
+
+class PublisherFTPTask(FTPTask):
+    """ """
+
+    __implements__ = FTPTask.__implements__
+
+
+    def execute(self):
+        """ """
+        server = self.channel.server
+        env = self.create_environment()
+        instream = self.request_data.getBodyStream()
+
+        request = server.request_factory(instream, self, env)
+        publish(request)
+
+
+    def create_environment(self):
+        request_data = self.request_data
+        channel = self.channel
+        server = channel.server
+
+        # This should probably change to reflect calling the FileSystem
+        # methods
+        env = {'command': request_data.command
+               'args': request_data.args
+               }
+
+
+        return env


=== Zope3/lib/python/Zope/Server/FTP/RecvChannel.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 Zope.Server.Counter import Counter
-        
-class RecvChannel(asyncore.dispatcher):
-    """ """
-
-    def __init__ (self, channel, client_addr, fd):
-        self.channel = channel
-        self.client_addr = client_addr
-        self.fd = fd
-        asyncore.dispatcher.__init__ (self)
-        self.bytes_in = Counter()
-
-        
-    def log (self, *ignore):
-        pass
-
-        
-    def handle_connect (self):
-        pass
-
-        
-    def writable (self):
-        return 0
-
-        
-    def recv (*args):
-        result = apply (asyncore.dispatcher.recv, args)
-        self = args[0]
-        self.bytes_in.increment(len(result))
-        return result
-
-        
-    buffer_size = 8192
-
-    
-    def handle_read (self):
-        block = self.recv (self.buffer_size)
-        if block:
-            try:
-                self.fd.write (block)
-            except IOError:
-                self.log_info ('got exception writing block...', 'error')
-
-                
-    def handle_close (self):
-        s = self.channel.server
-        s.total_files_in.increment()
-        s.total_bytes_in.increment(self.bytes_in.as_long())
-        self.fd.close()
-        self.channel.reply(226, 1)
-        self.close()
+##############################################################################
+#
+# 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 Zope.Server.Counter import Counter
+
+class RecvChannel(asyncore.dispatcher):
+    """ """
+
+    def __init__ (self, channel, client_addr, fd):
+        self.channel = channel
+        self.client_addr = client_addr
+        self.fd = fd
+        asyncore.dispatcher.__init__ (self)
+        self.bytes_in = Counter()
+
+
+    def log (self, *ignore):
+        pass
+
+
+    def handle_connect (self):
+        pass
+
+
+    def writable (self):
+        return 0
+
+
+    def recv (*args):
+        result = apply (asyncore.dispatcher.recv, args)
+        self = args[0]
+        self.bytes_in.increment(len(result))
+        return result
+
+
+    buffer_size = 8192
+
+
+    def handle_read (self):
+        block = self.recv (self.buffer_size)
+        if block:
+            try:
+                self.fd.write (block)
+            except IOError:
+                self.log_info ('got exception writing block...', 'error')
+
+
+    def handle_close (self):
+        s = self.channel.server
+        s.total_files_in.increment()
+        s.total_bytes_in.increment(self.bytes_in.as_long())
+        self.fd.close()
+        self.channel.reply(226, 1)
+        self.close()


=== Zope3/lib/python/Zope/Server/FTP/XmitChannel.py 1.1.2.1 => 1.1.2.2 ===
-#
-# 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 asynchat
-
-
-class XmitChannel(asynchat.async_chat, object):
-
-    # for an ethernet, you want this to be fairly large, in fact, it
-    # _must_ be large for performance comparable to an ftpd.  [64k] we
-    # ought to investigate automatically-sized buffers...
-    ac_out_buffer_size = 16384
-    
-    bytes_out = 0
-    
-    def __init__ (self, channel, client_addr=None):
-        self.channel = channel
-        self.client_addr = client_addr
-        super(XmitChannel, self).__init__()
-        
-        
-    def log (*args):
-        pass
-
-        
-    def readable (self):
-        return not self.connected
-
-        
-    def writable (self):
-        return 1
-
-        
-    def send (self, data):
-        result = super(XmitChannel, self).send(data)
-        self.bytes_out = self.bytes_out + result
-        return result
-
-        
-    def handle_error (self):
-        # usually this is to catch an unexpected disconnect.
-        # XXX: Helpfule for debugging
-        import traceback
-        traceback.print_exc()
-        self.log_info ('unexpected disconnect on data xmit channel', 'error')
-        try:
-            self.close()
-        except:
-            pass
-            
-    # TODO: there's a better way to do this.  we need to be able to
-    # put 'events' in the producer fifo.  to do this cleanly we need
-    # to reposition the 'producer' fifo as an 'event' fifo.
-    
-    # dummy function to suppress warnings caused by some FTP clients
-    def handle_connect(self):
-        pass
-
-            
-    def close (self):
-        c = self.channel
-        s = c.server
-        c.client_dc = None
-        s.total_files_out.increment()
-        s.total_bytes_out.increment (self.bytes_out)
-        if not len(self.producer_fifo):
-            c.reply(226, 1)
-        elif not c.closed:
-            c.reply(426)
-        del c
-        del s
-        del self.channel
-        asynchat.async_chat.close(self)
+##############################################################################
+#
+# 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 asynchat
+
+
+class XmitChannel(asynchat.async_chat, object):
+
+    # for an ethernet, you want this to be fairly large, in fact, it
+    # _must_ be large for performance comparable to an ftpd.  [64k] we
+    # ought to investigate automatically-sized buffers...
+    ac_out_buffer_size = 16384
+
+    bytes_out = 0
+
+    def __init__ (self, channel, client_addr=None):
+        self.channel = channel
+        self.client_addr = client_addr
+        super(XmitChannel, self).__init__()
+
+
+    def log (*args):
+        pass
+
+
+    def readable (self):
+        return not self.connected
+
+
+    def writable (self):
+        return 1
+
+
+    def send (self, data):
+        result = super(XmitChannel, self).send(data)
+        self.bytes_out = self.bytes_out + result
+        return result
+
+
+    def handle_error (self):
+        # usually this is to catch an unexpected disconnect.
+        # XXX: Helpfule for debugging
+        import traceback
+        traceback.print_exc()
+        self.log_info ('unexpected disconnect on data xmit channel', 'error')
+        try:
+            self.close()
+        except:
+            pass
+
+    # TODO: there's a better way to do this.  we need to be able to
+    # put 'events' in the producer fifo.  to do this cleanly we need
+    # to reposition the 'producer' fifo as an 'event' fifo.
+
+    # dummy function to suppress warnings caused by some FTP clients
+    def handle_connect(self):
+        pass
+
+
+    def close (self):
+        c = self.channel
+        s = c.server
+        c.client_dc = None
+        s.total_files_out.increment()
+        s.total_bytes_out.increment (self.bytes_out)
+        if not len(self.producer_fifo):
+            c.reply(226, 1)
+        elif not c.closed:
+            c.reply(426)
+        del c
+        del s
+        del self.channel
+        asynchat.async_chat.close(self)


=== Zope3/lib/python/Zope/Server/FTP/__init__.py 1.1.2.1 => 1.1.2.2 ===
-#
-# 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$
-"""
+##############################################################################
+#
+# 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$
+"""