trunk: backport fixes for FTPClientSession

This commit is contained in:
Marian Krivos 2012-02-04 17:39:15 +00:00
parent 8b70c37260
commit 73426e13e7
2 changed files with 273 additions and 264 deletions

View File

@ -77,67 +77,72 @@ public:
enum FileType enum FileType
{ {
TYPE_TEXT, // TYPE A (ASCII) TYPE_TEXT, // TYPE A (ASCII)
TYPE_BINARY // TYPE I (Image) TYPE_BINARY // TYPE I (Image)
}; };
FTPClientSession(); FTPClientSession();
/// Creates an FTPClientSession. /// Creates an FTPClientSession.
/// ///
/// Passive mode will be used for data transfers. /// Passive mode will be used for data transfers.
explicit FTPClientSession(const StreamSocket& socket); explicit FTPClientSession(const StreamSocket& socket);
/// Creates an FTPClientSession using the given /// Creates an FTPClientSession using the given
/// connected socket for the control connection. /// connected socket for the control connection.
/// ///
/// Passive mode will be used for data transfers. /// Passive mode will be used for data transfers.
FTPClientSession(const std::string& host, FTPClientSession(const std::string& host,
Poco::UInt16 port = FTP_PORT, Poco::UInt16 port = FTP_PORT,
const std::string& username = "", const std::string& username = "",
const std::string& password = ""); const std::string& password = "");
/// Creates an FTPClientSession using a socket connected /// Creates an FTPClientSession using a socket connected
/// to the given host and port. If username is supplied, /// to the given host and port. If username is supplied,
/// login is attempted. /// login is attempted.
/// ///
/// Passive mode will be used for data transfers. /// Passive mode will be used for data transfers.
virtual ~FTPClientSession(); virtual ~FTPClientSession();
/// Destroys the FTPClientSession. /// Destroys the FTPClientSession.
void setTimeout(const Poco::Timespan& timeout); void setTimeout(const Poco::Timespan& timeout);
/// Sets the timeout for socket operations. /// Sets the timeout for socket operations.
Poco::Timespan getTimeout() const; Poco::Timespan getTimeout() const;
/// Returns the timeout for socket operations. /// Returns the timeout for socket operations.
void setPassive(bool flag); void setPassive(bool flag, bool useRFC1738 = true);
/// Enables (default) or disables FTP passive mode for this session. /// Enables (default) or disables FTP passive mode for this session.
///
bool getPassive() const; /// If useRFC1738 is true (the default), the RFC 1738
/// Returns true iff passive mode is enabled for this connection. /// EPSV command is used (with a fallback to PASV if EPSV fails)
/// for switching to passive mode. The same applies to
void open(const std::string& host, /// EPRT and PORT for active connections.
Poco::UInt16 port,
const std::string& username = "", bool getPassive() const;
const std::string& password = ""); /// Returns true iff passive mode is enabled for this connection.
/// Opens the FTP connection to the given host and port.
/// If username is supplied, login is attempted. void open(const std::string& host,
Poco::UInt16 port,
const std::string& username = "",
const std::string& password = "");
/// Opens the FTP connection to the given host and port.
/// If username is supplied, login is attempted.
void login(const std::string& username, const std::string& password); void login(const std::string& username, const std::string& password);
/// Authenticates the user against the FTP server. Must be /// Authenticates the user against the FTP server. Must be
/// called before any other commands (except QUIT) can be sent. /// called before any other commands (except QUIT) can be sent.
/// ///
/// Sends a USER command followed by a PASS command with the /// Sends a USER command followed by a PASS command with the
/// respective arguments to the server. /// respective arguments to the server.
/// ///
/// Throws a FTPException in case of a FTP-specific error, or a /// Throws a FTPException in case of a FTP-specific error, or a
/// NetException in case of a general network communication failure. /// NetException in case of a general network communication failure.
void logout(); void logout();
void close(); void close();
/// Sends a QUIT command and closes the connection to the server. /// Sends a QUIT command and closes the connection to the server.
/// ///
/// Throws a FTPException in case of a FTP-specific error, or a /// Throws a FTPException in case of a FTP-specific error, or a
/// NetException in case of a general network communication failure. /// NetException in case of a general network communication failure.
@ -310,18 +315,18 @@ public:
/// and waits for a response. /// and waits for a response.
int sendCommand(const std::string& command, const std::string& arg, std::string& response); int sendCommand(const std::string& command, const std::string& arg, std::string& response);
/// Sends the given command verbatim to the server /// Sends the given command verbatim to the server
/// and waits for a response. /// and waits for a response.
bool isOpen() const; bool isOpen() const;
/// Returns true if the connection with FTP server is opened. /// Returns true if the connection with FTP server is opened.
bool isLoggedIn() const; bool isLoggedIn() const;
/// Returns true if the session is logged in. /// Returns true if the session is logged in.
protected: protected:
enum StatusClass enum StatusClass
{ {
FTP_POSITIVE_PRELIMINARY = 1, FTP_POSITIVE_PRELIMINARY = 1,
FTP_POSITIVE_COMPLETION = 2, FTP_POSITIVE_COMPLETION = 2,
FTP_POSITIVE_INTERMEDIATE = 3, FTP_POSITIVE_INTERMEDIATE = 3,
@ -350,22 +355,22 @@ protected:
void sendPASV(SocketAddress& addr); void sendPASV(SocketAddress& addr);
void parseAddress(const std::string& str, SocketAddress& addr); void parseAddress(const std::string& str, SocketAddress& addr);
void parseExtAddress(const std::string& str, SocketAddress& addr); void parseExtAddress(const std::string& str, SocketAddress& addr);
void endTransfer(); void endTransfer();
private: private:
FTPClientSession(const FTPClientSession&); FTPClientSession(const FTPClientSession&);
FTPClientSession& operator = (const FTPClientSession&); FTPClientSession& operator = (const FTPClientSession&);
std::string _host; std::string _host;
Poco::UInt16 _port; Poco::UInt16 _port;
DialogSocket* _pControlSocket; DialogSocket* _pControlSocket;
SocketStream* _pDataStream; SocketStream* _pDataStream;
bool _passiveMode; bool _passiveMode;
FileType _fileType; FileType _fileType;
bool _supports1738; bool _supports1738;
bool _serverReady; bool _serverReady;
bool _isLoggedIn; bool _isLoggedIn;
Poco::Timespan _timeout; Poco::Timespan _timeout;
}; };
@ -404,13 +409,13 @@ inline bool FTPClientSession::isPermanentNegative(int status)
inline bool FTPClientSession::isOpen() const inline bool FTPClientSession::isOpen() const
{ {
return _pControlSocket != 0; return _pControlSocket != 0;
} }
inline bool FTPClientSession::isLoggedIn() const inline bool FTPClientSession::isLoggedIn() const
{ {
return _isLoggedIn; return _isLoggedIn;
} }

View File

@ -40,7 +40,7 @@
#include "Poco/Net/ServerSocket.h" #include "Poco/Net/ServerSocket.h"
#include "Poco/Net/NetException.h" #include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h" #include "Poco/NumberFormatter.h"
#include <cctype> #include "Poco/Ascii.h"
using Poco::NumberFormatter; using Poco::NumberFormatter;
@ -51,83 +51,84 @@ namespace Net {
FTPClientSession::FTPClientSession(): FTPClientSession::FTPClientSession():
_port(0), _port(0),
_pControlSocket(0), _pControlSocket(0),
_pDataStream(0), _pDataStream(0),
_passiveMode(true), _passiveMode(true),
_fileType(TYPE_BINARY), _fileType(TYPE_BINARY),
_supports1738(true), _supports1738(true),
_serverReady(false), _serverReady(false),
_isLoggedIn(false), _isLoggedIn(false),
_timeout(DEFAULT_TIMEOUT) _timeout(DEFAULT_TIMEOUT)
{ {
} }
FTPClientSession::FTPClientSession(const StreamSocket& socket): FTPClientSession::FTPClientSession(const StreamSocket& socket):
_host(socket.address().host().toString()), _host(socket.address().host().toString()),
_port(socket.address().port()), _port(socket.address().port()),
_pControlSocket(new DialogSocket(socket)), _pControlSocket(new DialogSocket(socket)),
_pDataStream(0), _pDataStream(0),
_passiveMode(true), _passiveMode(true),
_fileType(TYPE_BINARY), _fileType(TYPE_BINARY),
_supports1738(true), _supports1738(true),
_serverReady(false), _serverReady(false),
_isLoggedIn(false), _isLoggedIn(false),
_timeout(DEFAULT_TIMEOUT) _timeout(DEFAULT_TIMEOUT)
{ {
_pControlSocket->setReceiveTimeout(_timeout); _pControlSocket->setReceiveTimeout(_timeout);
} }
FTPClientSession::FTPClientSession(const std::string& host, FTPClientSession::FTPClientSession(const std::string& host,
Poco::UInt16 port, Poco::UInt16 port,
const std::string& username, const std::string& username,
const std::string& password): const std::string& password):
_host(host), _host(host),
_port(port), _port(port),
_pControlSocket(new DialogSocket(SocketAddress(host, port))), _pControlSocket(new DialogSocket(SocketAddress(host, port))),
_pDataStream(0), _pDataStream(0),
_passiveMode(true), _passiveMode(true),
_fileType(TYPE_BINARY), _fileType(TYPE_BINARY),
_supports1738(true), _supports1738(true),
_serverReady(false), _serverReady(false),
_isLoggedIn(false), _isLoggedIn(false),
_timeout(DEFAULT_TIMEOUT) _timeout(DEFAULT_TIMEOUT)
{ {
if (!username.empty()) if (!username.empty())
login(username, password); login(username, password);
else else
_pControlSocket->setReceiveTimeout(_timeout); _pControlSocket->setReceiveTimeout(_timeout);
} }
FTPClientSession::~FTPClientSession() FTPClientSession::~FTPClientSession()
{ {
try { close(); } try { close(); }
catch (...) { } catch (...) { }
} }
void FTPClientSession::setTimeout(const Poco::Timespan& timeout) void FTPClientSession::setTimeout(const Poco::Timespan& timeout)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
_timeout = timeout; _timeout = timeout;
_pControlSocket->setReceiveTimeout(timeout); _pControlSocket->setReceiveTimeout(timeout);
} }
Poco::Timespan FTPClientSession::getTimeout() const Poco::Timespan FTPClientSession::getTimeout() const
{ {
return _timeout; return _timeout;
} }
void FTPClientSession::setPassive(bool flag) void FTPClientSession::setPassive(bool flag, bool useRFC1738)
{ {
_passiveMode = flag; _passiveMode = flag;
_supports1738 = useRFC1738;
} }
@ -138,85 +139,85 @@ bool FTPClientSession::getPassive() const
void FTPClientSession::open(const std::string& host, void FTPClientSession::open(const std::string& host,
Poco::UInt16 port, Poco::UInt16 port,
const std::string& username, const std::string& username,
const std::string& password) const std::string& password)
{ {
_host = host; _host = host;
_port = port; _port = port;
if (!username.empty()) if (!username.empty())
login(username, password); login(username, password);
else else
{ {
_pControlSocket = new DialogSocket(SocketAddress(_host, _port)); _pControlSocket = new DialogSocket(SocketAddress(_host, _port));
_pControlSocket->setReceiveTimeout(_timeout); _pControlSocket->setReceiveTimeout(_timeout);
} }
} }
void FTPClientSession::login(const std::string& username, const std::string& password) void FTPClientSession::login(const std::string& username, const std::string& password)
{ {
if (_isLoggedIn) logout(); if (_isLoggedIn) logout();
int status = FTP_POSITIVE_COMPLETION * 100; int status = FTP_POSITIVE_COMPLETION * 100;
std::string response; std::string response;
if (!_pControlSocket) if (!_pControlSocket)
{ {
_pControlSocket = new DialogSocket(SocketAddress(_host, _port)); _pControlSocket = new DialogSocket(SocketAddress(_host, _port));
_pControlSocket->setReceiveTimeout(_timeout); _pControlSocket->setReceiveTimeout(_timeout);
} }
if (!_serverReady) if (!_serverReady)
{ {
status = _pControlSocket->receiveStatusMessage(response); status = _pControlSocket->receiveStatusMessage(response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException("Cannot login to server", response); throw FTPException("Cannot login to server", response, status);
_serverReady = true; _serverReady = true;
} }
status = sendCommand("USER", username, response); status = sendCommand("USER", username, response);
if (isPositiveIntermediate(status)) if (isPositiveIntermediate(status))
status = sendCommand("PASS", password, response); status = sendCommand("PASS", password, response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException("Login denied", response); throw FTPException("Login denied", response, status);
setFileType(_fileType); setFileType(_fileType);
_isLoggedIn = true; _isLoggedIn = true;
} }
void FTPClientSession::logout() void FTPClientSession::logout()
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
if (_isLoggedIn) if (_isLoggedIn)
{ {
try { endTransfer(); } try { endTransfer(); }
catch (...) { } catch (...) { }
std::string response; std::string response;
sendCommand("QUIT", response); sendCommand("QUIT", response);
_isLoggedIn = false; _isLoggedIn = false;
} }
} }
void FTPClientSession::close() void FTPClientSession::close()
{ {
logout(); logout();
_pControlSocket->close(); _pControlSocket->close();
delete _pControlSocket; delete _pControlSocket;
_pControlSocket = 0; _pControlSocket = 0;
_serverReady = false; _serverReady = false;
} }
void FTPClientSession::setFileType(FTPClientSession::FileType type) void FTPClientSession::setFileType(FTPClientSession::FileType type)
{ {
std::string response; std::string response;
int status = sendCommand("TYPE", (type == TYPE_TEXT ? "A" : "I"), response); int status = sendCommand("TYPE", (type == TYPE_TEXT ? "A" : "I"), response);
if (!isPositiveCompletion(status)) throw FTPException("Cannot set file type", response); if (!isPositiveCompletion(status)) throw FTPException("Cannot set file type", response, status);
_fileType = type; _fileType = type;
} }
@ -234,16 +235,16 @@ std::string FTPClientSession::systemType()
if (isPositiveCompletion(status)) if (isPositiveCompletion(status))
return response.substr(4); return response.substr(4);
else else
throw FTPException("Cannot get remote system type", response); throw FTPException("Cannot get remote system type", response, status);
} }
void FTPClientSession::setWorkingDirectory(const std::string& path) void FTPClientSession::setWorkingDirectory(const std::string& path)
{ {
std::string response; std::string response;
int status = sendCommand("CWD", path, response); int status = sendCommand("CWD", path, response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException("Cannot change directory", response); throw FTPException("Cannot change directory", response, status);
} }
@ -254,66 +255,66 @@ std::string FTPClientSession::getWorkingDirectory()
if (isPositiveCompletion(status)) if (isPositiveCompletion(status))
return extractPath(response); return extractPath(response);
else else
throw FTPException("Cannot get current working directory", response); throw FTPException("Cannot get current working directory", response, status);
} }
void FTPClientSession::cdup() void FTPClientSession::cdup()
{ {
std::string response; std::string response;
int status = sendCommand("CDUP", response); int status = sendCommand("CDUP", response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException("Cannot change directory", response); throw FTPException("Cannot change directory", response, status);
} }
void FTPClientSession::rename(const std::string& oldName, const std::string& newName) void FTPClientSession::rename(const std::string& oldName, const std::string& newName)
{ {
std::string response; std::string response;
int status = sendCommand("RNFR", oldName, response); int status = sendCommand("RNFR", oldName, response);
if (!isPositiveIntermediate(status)) if (!isPositiveIntermediate(status))
throw FTPException(std::string("Cannot rename ") + oldName, response); throw FTPException(std::string("Cannot rename ") + oldName, response, status);
status = sendCommand("RNTO", newName, response); status = sendCommand("RNTO", newName, response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot rename to ") + newName, response); throw FTPException(std::string("Cannot rename to ") + newName, response, status);
} }
void FTPClientSession::remove(const std::string& path) void FTPClientSession::remove(const std::string& path)
{ {
std::string response; std::string response;
int status = sendCommand("DELE", path, response); int status = sendCommand("DELE", path, response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot remove " + path), response); throw FTPException(std::string("Cannot remove " + path), response, status);
} }
void FTPClientSession::createDirectory(const std::string& path) void FTPClientSession::createDirectory(const std::string& path)
{ {
std::string response; std::string response;
int status = sendCommand("MKD", path, response); int status = sendCommand("MKD", path, response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot create directory ") + path, response); throw FTPException(std::string("Cannot create directory ") + path, response, status);
} }
void FTPClientSession::removeDirectory(const std::string& path) void FTPClientSession::removeDirectory(const std::string& path)
{ {
std::string response; std::string response;
int status = sendCommand("RMD", path, response); int status = sendCommand("RMD", path, response);
if (!isPositiveCompletion(status)) if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot remove directory ") + path, response); throw FTPException(std::string("Cannot remove directory ") + path, response, status);
} }
std::istream& FTPClientSession::beginDownload(const std::string& path) std::istream& FTPClientSession::beginDownload(const std::string& path)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
delete _pDataStream; delete _pDataStream;
_pDataStream = 0; _pDataStream = 0;
_pDataStream = new SocketStream(establishDataConnection("RETR", path)); _pDataStream = new SocketStream(establishDataConnection("RETR", path));
return *_pDataStream; return *_pDataStream;
} }
@ -323,15 +324,15 @@ void FTPClientSession::endDownload()
endTransfer(); endTransfer();
} }
std::ostream& FTPClientSession::beginUpload(const std::string& path) std::ostream& FTPClientSession::beginUpload(const std::string& path)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
delete _pDataStream; delete _pDataStream;
_pDataStream = 0; _pDataStream = 0;
_pDataStream = new SocketStream(establishDataConnection("STOR", path)); _pDataStream = new SocketStream(establishDataConnection("STOR", path));
return *_pDataStream; return *_pDataStream;
} }
@ -344,12 +345,12 @@ void FTPClientSession::endUpload()
std::istream& FTPClientSession::beginList(const std::string& path, bool extended) std::istream& FTPClientSession::beginList(const std::string& path, bool extended)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
delete _pDataStream; delete _pDataStream;
_pDataStream = 0; _pDataStream = 0;
_pDataStream = new SocketStream(establishDataConnection(extended ? "LIST" : "NLST", path)); _pDataStream = new SocketStream(establishDataConnection(extended ? "LIST" : "NLST", path));
return *_pDataStream; return *_pDataStream;
} }
@ -359,39 +360,40 @@ void FTPClientSession::endList()
endTransfer(); endTransfer();
} }
void FTPClientSession::abort() void FTPClientSession::abort()
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
_pControlSocket->sendByte(DialogSocket::TELNET_IP); _pControlSocket->sendByte(DialogSocket::TELNET_IP);
_pControlSocket->synch(); _pControlSocket->synch();
std::string response; std::string response;
int status = sendCommand("ABOR", response); int status = sendCommand("ABOR", response);
if (status == 426) if (status == 426)
status = _pControlSocket->receiveStatusMessage(response); status = _pControlSocket->receiveStatusMessage(response);
if (status != 226) throw FTPException("Cannot abort transfer", response); if (status != 226)
throw FTPException("Cannot abort transfer", response, status);
} }
int FTPClientSession::sendCommand(const std::string& command, std::string& response) int FTPClientSession::sendCommand(const std::string& command, std::string& response)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
_pControlSocket->sendMessage(command); _pControlSocket->sendMessage(command);
return _pControlSocket->receiveStatusMessage(response); return _pControlSocket->receiveStatusMessage(response);
} }
int FTPClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response) int FTPClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
_pControlSocket->sendMessage(command, arg); _pControlSocket->sendMessage(command, arg);
return _pControlSocket->receiveStatusMessage(response); return _pControlSocket->receiveStatusMessage(response);
} }
@ -409,7 +411,7 @@ std::string FTPClientSession::extractPath(const std::string& response)
if (*it == '"') if (*it == '"')
{ {
++it; ++it;
if (it != end && *it != '"') break; if (it == end || (it != end && *it != '"')) break;
} }
path += *it++; path += *it++;
} }
@ -429,14 +431,15 @@ StreamSocket FTPClientSession::establishDataConnection(const std::string& comman
StreamSocket FTPClientSession::activeDataConnection(const std::string& command, const std::string& arg) StreamSocket FTPClientSession::activeDataConnection(const std::string& command, const std::string& arg)
{ {
if (!isOpen()) if (!isOpen())
throw FTPException("Connection is closed."); throw FTPException("Connection is closed.");
ServerSocket server(SocketAddress(_pControlSocket->address().host(), 0)); ServerSocket server(SocketAddress(_pControlSocket->address().host(), 0));
sendPortCommand(server.address()); sendPortCommand(server.address());
std::string response; std::string response;
int status = sendCommand(command, arg, response); int status = sendCommand(command, arg, response);
if (!isPositivePreliminary(status)) throw FTPException(command + " command failed", response); if (!isPositivePreliminary(status))
throw FTPException(command + " command failed", response, status);
if (server.poll(_timeout, Socket::SELECT_READ)) if (server.poll(_timeout, Socket::SELECT_READ))
return server.acceptConnection(); return server.acceptConnection();
else else
@ -450,7 +453,8 @@ StreamSocket FTPClientSession::passiveDataConnection(const std::string& command,
StreamSocket sock(sa); StreamSocket sock(sa);
std::string response; std::string response;
int status = sendCommand(command, arg, response); int status = sendCommand(command, arg, response);
if (!isPositivePreliminary(status)) throw FTPException(command + " command failed", response); if (!isPositivePreliminary(status))
throw FTPException(command + " command failed", response, status);
return sock; return sock;
} }
@ -499,7 +503,7 @@ bool FTPClientSession::sendEPRT(const SocketAddress& addr)
else if (isPermanentNegative(status)) else if (isPermanentNegative(status))
return false; return false;
else else
throw FTPException("EPRT command failed", response); throw FTPException("EPRT command failed", response, status);
} }
@ -517,7 +521,8 @@ void FTPClientSession::sendPORT(const SocketAddress& addr)
arg += NumberFormatter::format(port % 256); arg += NumberFormatter::format(port % 256);
std::string response; std::string response;
int status = sendCommand("PORT", arg, response); int status = sendCommand("PORT", arg, response);
if (!isPositiveCompletion(status)) throw FTPException("PORT command failed", response); if (!isPositiveCompletion(status))
throw FTPException("PORT command failed", response, status);
} }
@ -534,7 +539,7 @@ bool FTPClientSession::sendEPSV(SocketAddress& addr)
{ {
return false; return false;
} }
else throw FTPException("EPSV command failed", response); else throw FTPException("EPSV command failed", response, status);
} }
@ -542,7 +547,8 @@ void FTPClientSession::sendPASV(SocketAddress& addr)
{ {
std::string response; std::string response;
int status = sendCommand("PASV", response); int status = sendCommand("PASV", response);
if (!isPositiveCompletion(status)) throw FTPException("PASV command failed", response); if (!isPositiveCompletion(status))
throw FTPException("PASV command failed", response, status);
parseAddress(response, addr); parseAddress(response, addr);
} }
@ -554,19 +560,19 @@ void FTPClientSession::parseAddress(const std::string& str, SocketAddress& addr)
while (it != end && *it != '(') ++it; while (it != end && *it != '(') ++it;
if (it != end) ++it; if (it != end) ++it;
std::string host; std::string host;
while (it != end && std::isdigit(*it)) host += *it++; while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') { host += '.'; ++it; } if (it != end && *it == ',') { host += '.'; ++it; }
while (it != end && std::isdigit(*it)) host += *it++; while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') { host += '.'; ++it; } if (it != end && *it == ',') { host += '.'; ++it; }
while (it != end && std::isdigit(*it)) host += *it++; while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') { host += '.'; ++it; } if (it != end && *it == ',') { host += '.'; ++it; }
while (it != end && std::isdigit(*it)) host += *it++; while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') ++it; if (it != end && *it == ',') ++it;
Poco::UInt16 portHi = 0; Poco::UInt16 portHi = 0;
while (it != end && std::isdigit(*it)) { portHi *= 10; portHi += *it++ - '0'; } while (it != end && Poco::Ascii::isDigit(*it)) { portHi *= 10; portHi += *it++ - '0'; }
if (it != end && *it == ',') ++it; if (it != end && *it == ',') ++it;
Poco::UInt16 portLo = 0; Poco::UInt16 portLo = 0;
while (it != end && std::isdigit(*it)) { portLo *= 10; portLo += *it++ - '0'; } while (it != end && Poco::Ascii::isDigit(*it)) { portLo *= 10; portLo += *it++ - '0'; }
addr = SocketAddress(host, portHi*256 + portLo); addr = SocketAddress(host, portHi*256 + portLo);
} }
@ -582,23 +588,21 @@ void FTPClientSession::parseExtAddress(const std::string& str, SocketAddress& ad
if (it != end && *it == delim) ++it; if (it != end && *it == delim) ++it;
if (it != end && *it == delim) ++it; if (it != end && *it == delim) ++it;
Poco::UInt16 port = 0; Poco::UInt16 port = 0;
while (it != end && std::isdigit(*it)) { port *= 10; port += *it++ - '0'; } while (it != end && Poco::Ascii::isDigit(*it)) { port *= 10; port += *it++ - '0'; }
addr = SocketAddress(_pControlSocket->peerAddress().host(), port); addr = SocketAddress(_pControlSocket->peerAddress().host(), port);
} }
void FTPClientSession::endTransfer() void FTPClientSession::endTransfer()
{ {
if (!isOpen())
throw FTPException("Connection is closed.");
if (_pDataStream) if (_pDataStream)
{ {
delete _pDataStream; delete _pDataStream;
_pDataStream = 0; _pDataStream = 0;
std::string response; std::string response;
int status = _pControlSocket->receiveStatusMessage(response); int status = _pControlSocket->receiveStatusMessage(response);
if (!isPositiveCompletion(status)) throw FTPException("Data transfer failed", response); if (!isPositiveCompletion(status))
throw FTPException("Data transfer failed", response, status);
} }
} }