[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPStatusMessages.py:1.1.2.1 PassiveAcceptor.py:1.1.2.1 RecvChannel.py:1.1.2.1 XmitChannel.py:1.1.2.1 FTPCommandParser.py:1.1.2.2
Stephan Richter
srichter@cbu.edu
Wed, 3 Apr 2002 04:48:07 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP
In directory cvs.zope.org:/tmp/cvs-serv29646
Modified Files:
Tag: Zope3-Server-Branch
FTPCommandParser.py
Added Files:
Tag: Zope3-Server-Branch
FTPStatusMessages.py PassiveAcceptor.py RecvChannel.py
XmitChannel.py
Log Message:
More FTP server work done. It now can at least display a list of files in
a directory, however the simple FTP client in Unix still does not work.
I am getting closer though!
=== Added File Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.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: FTPStatusMessages.py,v 1.1.2.1 2002/04/03 09:48:06 srichter Exp $
"""
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'), # Size
214: ('-The following commands are recognized',
''),
215: ('%s Type: %s',), # Server Type
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.',),
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',),
599: ("Unknown type '%s'.",),
}
=== Added File Zope3/lib/python/Zope/Server/FTP/PassiveAcceptor.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: PassiveAcceptor.py,v 1.1.2.1 2002/04/03 09:48:06 srichter Exp $
"""
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()
=== Added File Zope3/lib/python/Zope/Server/FTP/RecvChannel.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: RecvChannel.py,v 1.1.2.1 2002/04/03 09:48:06 srichter Exp $
"""
import asyncore
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()
=== Added File Zope3/lib/python/Zope/Server/FTP/XmitChannel.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: XmitChannel.py,v 1.1.2.1 2002/04/03 09:48:06 srichter Exp $
"""
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/FTPCommandParser.py 1.1.2.1 => 1.1.2.2 ===
self.completed = 1
line = self.inbuf.strip()
+ print line
self.parseLine(line)
return len(s)