"""
FtpCube
Copyright (C) Michael Gilfix
This file is part of FtpCube.
You should have received a file COPYING containing license terms
along with this program; if not, write to Michael Gilfix
(mgilfix@eecs.tufts.edu) for a copy.
This version of FtpCube is open source; you can redistribute it and/or
modify it under the terms listed in the file COPYING.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
import exceptions
class ProtocolException(exceptions.Exception):
"""Base exception for protocol exceptions."""
def __init__(self, args=None):
self.args = args
class ProtocolInterface:
"""Protocol interface for FTP function.
This class defines an interface to allow FTP interaction over
multiple back-end protocols. Examples of back-end protocols
are the FTP control/data protocol, SFTP protocol, HTTP, etc.
Depending on the protocol, not all of these methods may be
implemented. As such, calling code should be prepared to handle
a NotImplementedError exception and inform the user. Such an
exception is non-fatal.
For many protocol commands, calling code may register an error
handling object to process any errors that occur during
execution. Error information is provided in the form of a
callback that may execute some time after the initial
scheduling of the command object."""
# Direction constants
DOWNLOAD = (1 << 0)
UPLOAD = (1 << 1)
# Transfer method constants
BINARY = (1 << 2)
ASCII = (1 << 3)
def __init__(self, **kwargs):
"""Initializes the back-end protocl implementation.
The following are recognized keyword arguments across all
back-end implementations:
'host' -> The host name or IP address to connect to
'port' -> The port to connect the FTP control session to
'logger' -> The logging implementation to use (from the
logger package)
'passive' -> Default passive mode
"""
raise NotImplementedError
def setPassive(self, passive):
"""Sets a boolean indicating whether this connection is passive.
Passive means that the client connects to the server in order
to transfer data. This is a firewall friendly mode."""
raise NotImplementedError
def getPassive(self):
"""Gets the passive mode for this connection as a boolean."""
raise NotImplementedError
def getDispatcher(self):
"""Gets the implementation thread dispatcher for this connection.
This dispatcher is used to dispatch command controls across a
connection. This takes care of any multi-threaded timing issues,
such as attempting to send multiple commands across the same
connection simulataneously."""
raise NotImplementedError
def destroy(self):
"""Destroys a protocol connection instance.
This quits the current control session."""
raise NotImplementedError
def addOutgoing(self, cmd, err_handler):
"""Adds an outgoing command object to be dispatched for execution."""
raise NotImplementedError
def initiateConnect(self, err_handler=None):
"""Initiates a protocol connection."""
raise NotImplementedError
def getWelcomeMessage(self, err_handler=None):
"""Reads a welcome message from the connection.
This method should be called after initiating a connection to the back
end protocol. If the back-end protocol does not support a welcome
message, then this method should remain unimplemented."""
raise NotImplementedError
def login(self, username, password, err_handler=None):
"""Performs a login within the supplied username and password.
This action should be performed after establishing the connection, and
after reading any welcome messages."""
raise NotImplementedError
def noop(self, err_handler=None):
"""Performs a no-op operation.
This command can double as a keep alive for the protocol control
session."""
raise NotImplementedError
def cwd(self, directory, err_handler=None):
"""Changes the current working directory.
The supplied directory is the directory to change to. Special implementation
handling of the "." and ".." entries may be necessary for the back-end
protocol. Calling implementations should expect these path conventions to
work."""
raise NotImplementedError
def pwd(self, err_handler=None):
"""Gets the current working directory."""
raise NotImplementedError
def delete(self, file, err_handler=None):
"""Deletes the specified file."""
raise NotImplementedError
def rename(self, old_name, new_name, err_handler=None):
"""Performs a rename of the specified file.
This operation assumes that the user is currently in the directory of the
file being renamed (the file must be in the current working directory)."""
raise NotImplementedError
def mkdir(self, directory, err_handler=None):
"""Creates a new directory with the supplied name in the current working
directory."""
raise NotImplementedError
def rmdir(self, directory, err_handler=None):
"""Removes the directory with the supplied name from the current working
directory."""
raise NotImplementedError
def abort(self, err_handler=None):
"""Aborts (cancels) the current executing command.
Depending on the timing of this execution, aborting the current command
may or may not be possible. In such cases where the command is already
executing and cannot be cancelled, this method acts as a no-op."""
raise NotImplementedError
def list(self, list_args, dispatch_status=None, err_handler=None):
"""Gets a listing of the current working directory.
The supplied list arguments are used to obtain more information from
the current listing. The dispatch status object allows calling code to
retrieve the results of the listing."""
raise NotImplementedError
def retrieveAscii(self, file, local_directory, dispatch_status=None, err_handler=None):
"""Performs the retrieval of an ascii encoded file.
This performs a retrieval of the supplied filename and stores the file in the
specified local directory. The dispatch status object will be updated with the
status of the transfer during its execution and upon completion."""
raise NotImplementedError
def uploadAscii(self, file, local_directory, dispatch_status=None, err_handler=None):
"""Performs an upload of an ascii encoded file.
This performs an upload of the supplied filename from the specified local
directory. The dispatch status object will be updated with the status of the
transfer during its execution and upon completion."""
raise NotImplementedError
def retrieveBinary(self, file, local_directory, dispatch_status=None, block_size=8192,
resume_size=None, err_handler=None):
"""Retrieves a binary file.
This performs a download of the supplied filename and stores the file in the
specified local directory. The dispatch status object will be updated with the
status of the transfer during its execution and upon completion."""
raise NotImplementedError
def uploadBinary(self, file, local_directory, dispatch_status=None, block_size=8192,
resume_size=None, err_handler=None):
"""Uploads a binary file.
This performs an upload of the supplied filename from the specified local
directory. The dispatch status object will be updated with the status of the
transfer during its execution and upon completion."""
raise NotImplementedError
|