[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - CommonFTPActivityLogger.py:1.1.2.1 FTPCommandParser.py:1.1.2.1 FTPServer.py:1.1.2.1 FTPServerChannel.py:1.1.2.1 FTPTask.py:1.1.2.1 IFTPCommandHandler.py:1.1.2.1 PublisherFTPTask.py:1.1.2.1 __init__.py:1.1.2.1
Stephan Richter
srichter@cbu.edu
Tue, 2 Apr 2002 00:08:07 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP
In directory cvs.zope.org:/tmp/cvs-serv6290/lib/python/Zope/Server/FTP
Added Files:
Tag: Zope3-Server-Branch
CommonFTPActivityLogger.py FTPCommandParser.py FTPServer.py
FTPServerChannel.py FTPTask.py IFTPCommandHandler.py
PublisherFTPTask.py __init__.py
Log Message:
Issue 53: Comment
- Created a bunch of interfaces that let us know what is going on.
- Split, updated and zopefied the Logger code.
- Reorganized dir structure in Zope.Server
- HTTP component split up in files (HTTP server works)
- Inserted Shane's skeleton FTP code (since I like his better than mine)
- Took a first cut at the Virtual File System (VFS) by copying and updating
medusa'a old filesys.py code.
=== Added File Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.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: CommonFTPActivityLogger.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""
class CommonActivityLogger:
"""This logger's output is
"""
pass
=== Added File Zope3/lib/python/Zope/Server/FTP/FTPCommandParser.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: FTPCommandParser.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""
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]
=== Added File Zope3/lib/python/Zope/Server/FTP/FTPServer.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: FTPServer.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""
from FTPServerChannel import FTPServerChannel
from ServerBase import ServerBase
class FTPServer(ServerBase):
"""Generic FTP Server"""
channel_class = FTPServerChannel
SERVER_IDENT = 'Zope.Server.FTPServer'
if __name__ == '__main__':
from 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()
=== Added File Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.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: FTPServerChannel.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""
from IFTPCommandHandler import IFTPCommandHandler
from ServerBase import ServerChannelBase
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
parser_class = FTPCommandParser
active_channels = {} # Class-specific channel tracker
next_channel_cleanup = [0] # Class-specific cleanup time
user_name = None
user_password = None
ascii_mode = 0
passive_mode = 0
def process_request(self, command):
"""Processes an FTP command.
Some commands use an alternate thread.
"""
assert isinstance(command, FTPCommandParser)
cmd = command.cmd
m = 'do_' + cmd.lower()
if hasattr(self, m):
# Quick processing
getattr(self, m)(command.args)
else:
# Process in another thread.
task = self.task_class(self, command, m)
if hasattr(task, m):
self.set_sync()
self.server.addTask(task)
else:
# TODO: reply "command unknown"
pass
def do_user(self, args):
self.user_name = args
self.reply(200) # Or whatever the code should be
def do_pass(self, args):
self.user_password = args
self.reply(200) # Or whatever the code should be
=== Added File Zope3/lib/python/Zope/Server/FTP/FTPTask.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: FTPTask.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""
import socket
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
############################################################
# Implementation methods for interface
# Zope.Server.ITask
def service(self):
"""Called to execute the task.
"""
try:
try:
self.start()
getattr(self, 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)
=== Added File Zope3/lib/python/Zope/Server/FTP/IFTPCommandHandler.py ===
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():
"""Abort operation. No read access required.
"""
def cmd_appe(filename, mode):
"""Append to a file. Write access required.
"""
def cmd_cdup():
"""Change to parent of current working directory.
"""
def cmd_cwd():
"""Change working directory.
"""
def cmd_dele():
"""Delete a file. Write access required.
"""
def cmd_help():
"""Give help information. No read access required.
"""
def cmd_list(path, match_pattern, long=1, recursive=0):
"""Give list files in a directory.
"""
def cmd_mdtm(filename):
"""Show last modification time of file.
Example output: 213 19960301204320
"""
def cmd_mkd(path):
"""Make a directory. Write access required.
"""
def cmd_mode(type):
"""Set file transfer mode. No read access required. Obselete.
"""
def cmd_nlst(path, match_pattern, long=0, recursive=0):
"""Give name list of files in directory.
"""
def cmd_noop():
"""Do nothing. No read access required.
"""
def cmd_pass(password):
"""Specify password.
"""
def cmd_pasv():
"""Prepare for server-to-server transfer. No read access required.
"""
def cmd_port(ip, port):
"""Specify data connection port. No read access required.
"""
def cmd_pwd():
"""Print the current working directory.
"""
def cmd_quit():
"""Terminate session. No read access required.
"""
def cmd_rest(position):
"""Restart incomplete transfer.
"""
def cmd_retr(filename):
"""Retrieve a file.
"""
def cmd_rmd(path):
"""Remove a directory. Write access required.
"""
def cmd_rnfr(filename):
"""Specify rename-from file name. Write access required.
"""
def cmd_rnto(filename):
"""Specify rename-to file name. Write access required.
"""
def cmd_size(filename):
"""Return size of file.
"""
def cmd_stat(filename):
"""Return status of server. No read access required.
"""
def cmd_stor(filename, mode):
"""Store a file. Write access required.
"""
def cmd_stru(type):
"""Set file transfer structure. Obselete."""
def cmd_syst():
"""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(type, byte_size):
"""Specify data transfer type. No read access required.
"""
def cmd_user(username):
"""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)', #!
}
=== Added File Zope3/lib/python/Zope/Server/FTP/PublisherFTPTask.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: PublisherFTPTask.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""
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
=== Added File Zope3/lib/python/Zope/Server/FTP/__init__.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: __init__.py,v 1.1.2.1 2002/04/02 05:08:06 srichter Exp $
"""