[Zope3-checkins] CVS: Zope3/src/zope/server/ftp - __init__.py:1.1.2.1 commonftpactivitylogger.py:1.1.2.1 ftpserver.py:1.1.2.1 ftpserverchannel.py:1.1.2.1 ftpstatusmessages.py:1.1.2.1 osemulators.py:1.1.2.1 passiveacceptor.py:1.1.2.1 publisherfilesystemaccess.py:1.1.2.1 publisherftpserver.py:1.1.2.1 publisherftpserverchannel.py:1.1.2.1 recvchannel.py:1.1.2.1 testfilesystemaccess.py:1.1.2.1 xmitchannel.py:1.1.2.1
Jim Fulton
jim@zope.com
Mon, 23 Dec 2002 14:33:21 -0500
Update of /cvs-repository/Zope3/src/zope/server/ftp
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/server/ftp
Added Files:
Tag: NameGeddon-branch
__init__.py commonftpactivitylogger.py ftpserver.py
ftpserverchannel.py ftpstatusmessages.py osemulators.py
passiveacceptor.py publisherfilesystemaccess.py
publisherftpserver.py publisherftpserverchannel.py
recvchannel.py testfilesystemaccess.py xmitchannel.py
Log Message:
Initial renaming before debugging
=== Added File Zope3/src/zope/server/ftp/__init__.py ===
#
# This file is necessary to make this directory a package.
=== Added File Zope3/src/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/12/23 19:33:19 jim Exp $
"""
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())
message = '%s [%s] "%s %s"' % (task.channel.username,
time.strftime('%Y/%m/%d %H:%M', now),
task.m_name[4:].upper(),
task.channel.cwd,
)
self.output.logRequest('127.0.0.1', message)
=== Added File Zope3/src/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/12/23 19:33:19 jim Exp $
"""
import asyncore
from zope.server.ftp.ftpserverchannel import FTPServerChannel
from zope.server.serverbase import ServerBase
from zope.server.interfaces.vfs import IFilesystemAccess
class FTPServer(ServerBase):
"""Generic FTP Server"""
channel_class = FTPServerChannel
SERVER_IDENT = 'Zope.Server.FTPServer'
def __init__(self, ip, port, fs_access, *args, **kw):
assert IFilesystemAccess.isImplementedBy(fs_access)
self.fs_access = fs_access
super(FTPServer, self).__init__(ip, port, *args, **kw)
if __name__ == '__main__':
from zope.server.taskthreads import ThreadedTaskDispatcher
from zope.server.vfs.osfilesystem import OSFileSystem
from zope.server.vfs.testfilesystemaccess import TestFilesystemAccess
td = ThreadedTaskDispatcher()
td.setThreadCount(4)
fs = OSFileSystem('/')
fs_access = TestFilesystemAccess(fs)
FTPServer('', 8021, fs_access, 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/src/zope/server/ftp/ftpserverchannel.py === (446/546 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: ftpserverchannel.py,v 1.1.2.1 2002/12/23 19:33:19 jim Exp $
"""
import posixpath
import stat
import socket
import time
from zope.server.linereceiver.lineserverchannel import LineServerChannel
from zope.server.ftp.ftpstatusmessages import status_msgs
from zope.server.ftp.osemulators import ls_longify
from zope.server.interfaces.ftp import IFTPCommandHandler
from zope.server.ftp.passiveacceptor import PassiveAcceptor
from zope.server.ftp.recvchannel import RecvChannel
from zope.server.ftp.xmitchannel import XmitChannel, ApplicationXmitStream
from zope.server.vfs.usernamepassword import UsernamePassword
from zope.exceptions import Unauthorized
class FTPServerChannel(LineServerChannel):
"""The FTP Server Channel represents a connection to a particular
client. We can therefore store information here."""
__implements__ = LineServerChannel.__implements__, IFTPCommandHandler
# List of commands that are always available
special_commands = ('cmd_quit', 'cmd_type', 'cmd_noop', 'cmd_user',
'cmd_pass')
# These are the commands that are accessing the filesystem.
# Since this could be also potentially a longer process, these commands
# are also the ones that are executed in a different thread.
thread_commands = ('cmd_appe', 'cmd_cdup', 'cmd_cwd', 'cmd_dele',
[-=- -=- -=- 446 lines omitted -=- -=- -=-]
file_list = fs.listdir(path, long)
else:
file_list = [ (posixpath.split(path)[1], fs.stat(path)) ]
# Make a pretty unix-like FTP output
if long:
file_list = map(ls_longify, file_list)
return ''.join(map(lambda line: line + '\r\n', file_list))
def connectDataChannel(self, cdc):
pa = self.passive_acceptor
if pa:
# PASV mode.
if pa.ready:
# a connection has already been made.
conn, addr = pa.ready
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.
# FTP Explorer is known to do this.
else:
# not in PASV mode.
ip, port = self.client_addr
cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM)
if self.bind_local_minus_one:
cdc.bind(('', self.server.port - 1))
try:
cdc.connect((ip, port))
except socket.error, err:
cdc.close('NO_DATA_CONN')
def notifyClientDCClosing(self, *reply_args):
if self.client_dc is not None:
self.client_dc = None
if reply_args:
self.reply(*reply_args)
def close(self):
LineServerChannel.close(self)
# Make sure the client DC gets closed too.
cdc = self.client_dc
if cdc is not None:
self.client_dc = None
cdc.close()
=== Added File Zope3/src/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/12/23 19:33:19 jim Exp $
"""
status_msgs = {
'OPEN_DATA_CONN' : '150 Opening %s mode data connection for file list',
'OPEN_CONN' : '150 Opening %s connection for %s',
'SUCCESS_200' : '200 %s command successful.',
'TYPE_SET_OK' : '200 Type set to %s.',
'STRU_OK' : '200 STRU F Ok.',
'MODE_OK' : '200 MODE S Ok.',
'FILE_DATE' : '213 %4d%02d%02d%02d%02d%02d',
'FILE_SIZE' : '213 %d Bytes',
'HELP_START' : '214-The following commands are recognized',
'HELP_END' : '214 Help done.',
'SERVER_TYPE' : '215 %s Type: %s',
'SERVER_READY' : '220 %s FTP server (Zope Async/Thread V0.1) ready.',
'GOODBYE' : '221 Goodbye.',
'SUCCESS_226' : '226 %s command successful.',
'TRANS_SUCCESS' : '226 Transfer successful.',
'PASV_MODE_MSG' : '227 Entering Passive Mode (%s,%d,%d)',
'LOGIN_SUCCESS' : '230 Login Successful.',
'SUCCESS_250' : '250 %s command successful.',
'SUCCESS_257' : '257 %s command successful.',
'ALREADY_CURRENT' : '257 "%s" is the current directory.',
'PASS_REQUIRED' : '331 Password required',
'RESTART_TRANSFER' : '350 Restarting at %d. Send STORE or '
'RETRIEVE to initiate transfer.',
'READY_FOR_DEST' : '350 File exists, ready for destination.',
'NO_DATA_CONN' : "425 Can't build data connection",
'TRANSFER_ABORTED' : '426 Connection closed; transfer aborted.',
'CMD_UNKNOWN' : "500 '%s': command not understood.",
'INTERNAL_ERROR' : "500 Internal error: %s",
'ERR_ARGS' : '500 Bad command arguments',
'MODE_UNKOWN' : '502 Unimplemented MODE type',
'WRONG_BYTE_SIZE' : '504 Byte size must be 8',
'STRU_UNKNOWN' : '504 Unimplemented STRU type',
'NOT_AUTH' : "530 You are not authorized to perform the "
"'%s' command",
'LOGIN_REQUIRED' : '530 Please log in with USER and PASS',
'LOGIN_MISMATCH' : '530 The username and password do not match.',
'ERR_NO_LIST' : '550 Could not list directory or file: %s',
'ERR_NO_DIR' : '550 "%s": No such directory.',
'ERR_NO_FILE' : '550 "%s": No such file.',
'ERR_NO_DIR_FILE' : '550 "%s": No such file or directory.',
'ERR_IS_NOT_FILE' : '550 "%s": Is not a file',
'ERR_CREATE_FILE' : '550 Error creating file.',
'ERR_CREATE_DIR' : '550 Error creating directory: %s',
'ERR_DELETE_FILE' : '550 Error deleting file: %s',
'ERR_DELETE_DIR' : '550 Error removing directory: %s',
'ERR_OPEN_READ' : '553 Could not open file for reading: %s',
'ERR_OPEN_WRITE' : '553 Could not open file for writing: %s',
'ERR_IO' : '553 I/O Error: %s',
'ERR_RENAME' : '560 Could not rename "%s" to "%s": %s',
'ERR_RNFR_SOURCE' : '560 No source filename specify. Call RNFR first.',
}
=== Added File Zope3/src/zope/server/ftp/osemulators.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.
#
##############################################################################
"""OS-Emulator Package
Simulates OS-level directory listing output for *nix and MS-DOS (including
Windows NT).
$Id: osemulators.py,v 1.1.2.1 2002/12/23 19:33:19 jim Exp $
"""
import stat
import datetime
mode_table = {
'0':'---',
'1':'--x',
'2':'-w-',
'3':'-wx',
'4':'r--',
'5':'r-x',
'6':'rw-',
'7':'rwx'
}
def ls_longify((filename, stat_info)):
"""Formats a directory entry similarly to the 'ls' command.
"""
# Note that we expect a little deviance from the result of os.stat():
# we expect the ST_UID and ST_GID fields to contain user IDs.
username = str(stat_info[stat.ST_UID])[:8]
grpname = str(stat_info[stat.ST_GID])[:8]
mode_octal = ('%o' % stat_info[stat.ST_MODE])[-3:]
mode = ''.join(map(mode_table.get, mode_octal))
if stat.S_ISDIR (stat_info[stat.ST_MODE]):
dirchar = 'd'
else:
dirchar = '-'
date = ls_date(datetime.datetime.now(), stat_info[stat.ST_MTIME])
return '%s%s %3d %-8s %-8s %8d %s %s' % (
dirchar,
mode,
stat_info[stat.ST_NLINK],
username,
grpname,
stat_info[stat.ST_SIZE],
date,
filename
)
def ls_date(now, t):
"""Emulate the 'ls' command's date field. It has two formats.
If the date is more than 180 days in the past or future, then
it's like this:
Oct 19 1995
otherwise, it looks like this:
Oct 19 17:33
"""
if abs((now - t).days) > 180:
return t.strftime('%b %d, %Y')
else:
return t.strftime('%b %d %H:%M')
def msdos_longify((file, stat_info)):
"""This matches the output of NT's ftp server (when in MSDOS mode)
exactly.
"""
if stat.S_ISDIR(stat_info[stat.ST_MODE]):
dir = '<DIR>'
else:
dir = ' '
date = msdos_date(stat_info[stat.ST_MTIME])
return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file)
def msdos_date(t):
"""Emulate MS-DOS 'dir' command. Example:
09-19-95 05:33PM
"""
return t.strftime('%m-%d-%y %H:%M%p')
=== Added File Zope3/src/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/12/23 19:33:19 jim 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()
conn.setblocking(0)
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/src/zope/server/ftp/publisherfilesystemaccess.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.
#
##############################################################################
"""Implementation of IFilesystemAccess intended only for testing.
$Id: publisherfilesystemaccess.py,v 1.1.2.1 2002/12/23 19:33:19 jim Exp $
"""
from cStringIO import StringIO
from zope.exceptions import Unauthorized
from zope.app.security.registries.principalregistry import principalRegistry
from zope.server.vfs.publisherfilesystem import PublisherFileSystem
from zope.server.interfaces.vfs import IFilesystemAccess
from zope.server.interfaces.vfs import IUsernamePassword
class PublisherFilesystemAccess:
__implements__ = IFilesystemAccess
def __init__(self, request_factory):
self.request_factory = request_factory
def authenticate(self, credentials):
assert IUsernamePassword.isImplementedBy(credentials)
env = {'credentials' : credentials}
request = self.request_factory(StringIO(''), StringIO(), env)
id = principalRegistry.authenticate(request)
if id is None:
raise Unauthorized
def open(self, credentials):
return PublisherFileSystem(credentials, self.request_factory)
=== Added File Zope3/src/zope/server/ftp/publisherftpserver.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: publisherftpserver.py,v 1.1.2.1 2002/12/23 19:33:19 jim Exp $
"""
from zope.server.ftp.ftpserver import FTPServer
from zope.server.ftp.publisherfilesystemaccess import PublisherFilesystemAccess
class PublisherFTPServer(FTPServer):
"""Generic FTP Server"""
def __init__(self, request_factory, name, ip, port, *args, **kw):
self.request_factory = request_factory
fs_access = PublisherFilesystemAccess(request_factory)
super(PublisherFTPServer, self).__init__(ip, port, fs_access,
*args, **kw)
=== Added File Zope3/src/zope/server/ftp/publisherftpserverchannel.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: publisherftpserverchannel.py,v 1.1.2.1 2002/12/23 19:33:19 jim Exp $
"""
from zope.server.ftp.ftpserverchannel import FTPServerChannel
class PublisherFTPServerChannel(FTPServerChannel):
"""The FTP Server Channel represents a connection to a particular
client. We can therefore store information here."""
__implements__ = FTPServerChannel.__implements__
def authenticate(self):
if self._getFilesystem()._authenticate():
return 1, 'User successfully authenticated.'
else:
return 0, 'User could not be authenticated.'
=== Added File Zope3/src/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/12/23 19:33:19 jim Exp $
"""
from zope.server.serverchannelbase import ChannelBaseClass
from zope.server.buffers import OverflowableBuffer
from zope.server.interfaces.interfaces import ITask
class RecvChannel(ChannelBaseClass):
""" """
complete_transfer = 0
_fileno = None # provide a default for asyncore.dispatcher._fileno
def __init__ (self, control_channel, finish_args):
self.control_channel = control_channel
self.finish_args = finish_args
self.inbuf = OverflowableBuffer(control_channel.adj.inbuf_overflow)
ChannelBaseClass.__init__(self, None, None, control_channel.adj)
# Note that this channel starts out in async mode.
def writable (self):
return 0
def handle_connect (self):
pass
def received (self, data):
if data:
self.inbuf.append(data)
def handle_close (self):
"""Client closed, indicating EOF."""
c = self.control_channel
task = FinishedRecvTask(c, self.inbuf, self.finish_args)
self.complete_transfer = 1
self.close()
c.start_task(task)
def close(self, *reply_args):
try:
c = self.control_channel
if c is not None:
self.control_channel = None
if not self.complete_transfer and not reply_args:
# Not all data transferred
reply_args = ('TRANSFER_ABORTED',)
c.notifyClientDCClosing(*reply_args)
finally:
if self.socket is not None:
# XXX asyncore.dispatcher.close() doesn't like socket == None
ChannelBaseClass.close(self)
class FinishedRecvTask:
__implements__ = ITask
def __init__(self, control_channel, inbuf, finish_args):
self.control_channel = control_channel
self.inbuf = inbuf
self.finish_args = finish_args
############################################################
# Implementation methods for interface
# Zope.Server.ITask
def service(self):
"""Called to execute the task.
"""
close_on_finish = 0
c = self.control_channel
try:
try:
c.finishedRecv(self.inbuf, self.finish_args)
except socket.error:
close_on_finish = 1
if c.adj.log_socket_errors:
raise
finally:
c.end_task(close_on_finish)
def cancel(self):
'See Zope.Server.ITask.ITask'
self.control_channel.close_when_done()
def defer(self):
'See Zope.Server.ITask.ITask'
pass
#
############################################################
=== Added File Zope3/src/zope/server/ftp/testfilesystemaccess.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.
#
##############################################################################
"""Implementation of IFilesystemAccess intended only for testing.
$Id: testfilesystemaccess.py,v 1.1.2.1 2002/12/23 19:33:19 jim Exp $
"""
from zope.server.interfaces.vfs import IFilesystemAccess
from zope.server.interfaces.vfs import IUsernamePassword
from zope.exceptions import Unauthorized
class TestFilesystemAccess:
__implements__ = IFilesystemAccess
passwords = {'foo': 'bar'}
def __init__(self, fs):
self.fs = fs
def authenticate(self, credentials):
if not IUsernamePassword.isImplementedBy(credentials):
raise Unauthorized
name = credentials.getUserName()
if not (name in self.passwords):
raise Unauthorized
if credentials.getPassword() != self.passwords[name]:
raise Unauthorized
def open(self, credentials):
self.authenticate(credentials)
return self.fs
=== Added File Zope3/src/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/12/23 19:33:19 jim Exp $
"""
from zope.server.serverchannelbase import ChannelBaseClass
class XmitChannel(ChannelBaseClass):
opened = 0
_fileno = None # provide a default for asyncore.dispatcher._fileno
def __init__ (self, control_channel, ok_reply_args):
self.control_channel = control_channel
self.ok_reply_args = ok_reply_args
self.set_sync()
ChannelBaseClass.__init__(self, None, None, control_channel.adj)
def _open(self):
"""Signal the client to open the connection."""
self.opened = 1
self.control_channel.reply(*self.ok_reply_args)
self.control_channel.connectDataChannel(self)
def write(self, data):
if self.control_channel is None:
raise IOError, 'Client FTP connection closed'
if not self.opened:
self._open()
ChannelBaseClass.write(self, data)
def readable(self):
return not self.connected
def handle_read(self):
# This is only called when making the connection.
try:
self.recv(1)
except:
# The connection failed.
self.close('NO_DATA_CONN')
def handle_connect(self):
pass
def handle_comm_error(self):
self.close('TRANSFER_ABORTED')
def close(self, *reply_args):
try:
c = self.control_channel
if c is not None:
self.control_channel = None
if not reply_args:
if not len(self.outbuf):
# All data transferred
if not self.opened:
# Zero-length file
self._open()
reply_args = ('TRANS_SUCCESS',)
else:
# Not all data transferred
reply_args = ('TRANSFER_ABORTED',)
c.notifyClientDCClosing(*reply_args)
finally:
if self.socket is not None:
# XXX asyncore.dispatcher.close() doesn't like socket == None
ChannelBaseClass.close(self)
class ApplicationXmitStream:
"""Provide stream output, remapping close() to close_when_done().
"""
def __init__(self, xmit_channel):
self.write = xmit_channel.write
self.flush = xmit_channel.flush
self.close = xmit_channel.close_when_done