Logo Search packages:      
Sourcecode: poco version File versions  Download package

FTPClientSession.cpp

//
// FTPClientSession.cpp
//
// $Id: //poco/1.2/Net/src/FTPClientSession.cpp#1 $
//
// Library: Net
// Package: FTP
// Module:  FTPClientSession
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#include "Poco/Net/FTPClientSession.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include <ctype.h>


using Poco::NumberFormatter;


namespace Poco {
namespace Net {


FTPClientSession::FTPClientSession(const StreamSocket& socket):
      _controlSocket(socket),
      _pDataStream(0),
      _passiveMode(true),
      _fileType(TYPE_BINARY),
      _supports1738(true),
      _isOpen(true),
      _timeout(DEFAULT_TIMEOUT)
{
      _controlSocket.setReceiveTimeout(_timeout);
}

      
00066 FTPClientSession::FTPClientSession(const std::string& host, Poco::UInt16 port):
      _controlSocket(SocketAddress(host, port)),
      _pDataStream(0),
      _passiveMode(true),
      _fileType(TYPE_BINARY),
      _supports1738(true),
      _isOpen(true),
      _timeout(DEFAULT_TIMEOUT)
{
      _controlSocket.setReceiveTimeout(_timeout);
}


00079 FTPClientSession::~FTPClientSession()
{
      try
      {
            close();
      }
      catch (...)
      {
      }
}


00091 void FTPClientSession::setTimeout(const Poco::Timespan& timeout)
{
      _timeout = timeout;
      _controlSocket.setReceiveTimeout(timeout);
}

      
00098 Poco::Timespan FTPClientSession::getTimeout() const
{
      return _timeout;
}


00104 void FTPClientSession::setPassive(bool flag)
{
      _passiveMode = flag;
}

      
00110 bool FTPClientSession::getPassive() const
{
      return _passiveMode;
}


00116 void FTPClientSession::login(const std::string& username, const std::string& password)
{
      std::string response;
      int status = _controlSocket.receiveStatusMessage(response);
      if (!isPositiveCompletion(status)) throw FTPException("Cannot login to server", response);
      status = sendCommand("USER", username, response);
      if (isPositiveIntermediate(status))
            status = sendCommand("PASS", password, response);
      if (!isPositiveCompletion(status)) throw FTPException("Login denied", response);
      setFileType(_fileType);
}


00129 void FTPClientSession::close()
{
      if (_isOpen)
      {
            try
            {
                  endTransfer(); 
            }
            catch (...)
            {
            }
            std::string response;
            sendCommand("QUIT", response);
            _controlSocket.close();
            _isOpen = false;
      }
}


00148 void FTPClientSession::setFileType(FTPClientSession::FileType type)
{
      std::string response;
      int status = sendCommand("TYPE", (type == TYPE_TEXT ? "A" : "I"), response);
      if (!isPositiveCompletion(status)) throw FTPException("Cannot set file type", response);
      _fileType = type;
}


00157 FTPClientSession::FileType FTPClientSession::getFileType() const
{
      return _fileType;
}


00163 std::string FTPClientSession::systemType()
{
      std::string response;
      int status = sendCommand("SYST", response);
      if (isPositiveCompletion(status))
            return response.substr(4);
      else
            throw FTPException("Cannot get remote system type", response);
}


00174 void FTPClientSession::setWorkingDirectory(const std::string& path)
{
      std::string response;
      int status = sendCommand("CWD", path, response);
      if (!isPositiveCompletion(status)) throw FTPException("Cannot change directory", response);
}


00182 std::string FTPClientSession::getWorkingDirectory()
{
      std::string response;
      int status = sendCommand("PWD", response);
      if (isPositiveCompletion(status))
            return extractPath(response);
      else
            throw FTPException("Cannot get current working directory", response);
}


00193 void FTPClientSession::cdup()
{
      std::string response;
      int status = sendCommand("CDUP", response);
      if (!isPositiveCompletion(status)) throw FTPException("Cannot change directory", response);
}

      
00201 void FTPClientSession::rename(const std::string& oldName, const std::string& newName)
{
      std::string response;
      int status = sendCommand("RNFR", oldName, response);
      if (!isPositiveIntermediate(status)) throw FTPException(std::string("Cannot rename ") + oldName, response);
      status = sendCommand("RNTO", newName, response);
      if (!isPositiveCompletion(status)) throw FTPException(std::string("Cannot rename to ") + newName, response);
}

      
00211 void FTPClientSession::remove(const std::string& path)
{
      std::string response;
      int status = sendCommand("DELE", path, response);
      if (!isPositiveCompletion(status)) throw FTPException(std::string("Cannot remove " + path), response);
}


00219 void FTPClientSession::createDirectory(const std::string& path)
{
      std::string response;
      int status = sendCommand("MKD", path, response);
      if (!isPositiveCompletion(status)) throw FTPException(std::string("Cannot create directory ") + path, response);
}


00227 void FTPClientSession::removeDirectory(const std::string& path)
{
      std::string response;
      int status = sendCommand("RMD", path, response);
      if (!isPositiveCompletion(status)) throw FTPException(std::string("Cannot remove directory ") + path, response);
}


00235 std::istream& FTPClientSession::beginDownload(const std::string& path)
{
      delete _pDataStream;
      _pDataStream = 0;
      _pDataStream = new SocketStream(establishDataConnection("RETR", path));
      return *_pDataStream;
}

      
00244 void FTPClientSession::endDownload()
{
      endTransfer();
}

      
00250 std::ostream& FTPClientSession::beginUpload(const std::string& path)
{
      delete _pDataStream;
      _pDataStream = 0;
      _pDataStream = new SocketStream(establishDataConnection("STOR", path));
      return *_pDataStream;
}


00259 void FTPClientSession::endUpload()
{
      endTransfer();
}


00265 std::istream& FTPClientSession::beginList(const std::string& path, bool extended)
{
      delete _pDataStream;
      _pDataStream = 0;
      _pDataStream = new SocketStream(establishDataConnection(extended ? "LIST" : "NLST", path));
      return *_pDataStream;
}


00274 void FTPClientSession::endList()
{
      endTransfer();
}

      
00280 void FTPClientSession::abort()
{
      _controlSocket.sendByte(DialogSocket::TELNET_IP);
      _controlSocket.synch();
      std::string response;
      int status = sendCommand("ABOR", response);
      if (status == 426)
            status = _controlSocket.receiveStatusMessage(response);
      if (status != 226) throw FTPException("Cannot abort transfer", response);
}


00292 int FTPClientSession::sendCommand(const std::string& command, std::string& response)
{
      _controlSocket.sendMessage(command);
      return _controlSocket.receiveStatusMessage(response);
}


00299 int FTPClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response)
{
      _controlSocket.sendMessage(command, arg);
      return _controlSocket.receiveStatusMessage(response);
}


std::string FTPClientSession::extractPath(const std::string& response)
{
      std::string path;
      std::string::const_iterator it  = response.begin();
      std::string::const_iterator end = response.end();
      while (it != end && *it != '"') ++it;
      if (it != end)
      {
            ++it;
            while (it != end)
            {
                  if (*it == '"')
                  {
                        ++it;
                        if (it != end && *it != '"') break;
                  }
                  path += *it++;
            }
      }
      return path;
}


StreamSocket FTPClientSession::establishDataConnection(const std::string& command, const std::string& arg)
{
      if (_passiveMode)
            return passiveDataConnection(command, arg);
      else
            return activeDataConnection(command, arg);
}


StreamSocket FTPClientSession::activeDataConnection(const std::string& command, const std::string& arg)
{
      ServerSocket server(SocketAddress(_controlSocket.address().host(), 0));
      sendPortCommand(server.address());
      std::string response;
      int status = sendCommand(command, arg, response);
      if (!isPositivePreliminary(status)) throw FTPException(command + " command failed", response);
      if (server.poll(_timeout, Socket::SELECT_READ))
            return server.acceptConnection();
      else
            throw FTPException("The server has not initiated a data connection");
}


StreamSocket FTPClientSession::passiveDataConnection(const std::string& command, const std::string& arg)
{
      SocketAddress sa(sendPassiveCommand());
      StreamSocket sock(sa);
      std::string response;
      int status = sendCommand(command, arg, response);
      if (!isPositivePreliminary(status)) throw FTPException(command + " command failed", response);
      return sock;
}


void FTPClientSession::sendPortCommand(const SocketAddress& addr)
{
      if (_supports1738)
      {
            if (sendEPRT(addr))
                  return;
            else
                  _supports1738 = false;
      }
      sendPORT(addr);
}


SocketAddress FTPClientSession::sendPassiveCommand()
{
      SocketAddress addr;
      if (_supports1738)
      {
            if (sendEPSV(addr))
                  return addr;
            else
                  _supports1738 = false;
      }
      sendPASV(addr);
      return addr;
}


bool FTPClientSession::sendEPRT(const SocketAddress& addr)
{
      std::string arg("|");
      arg += addr.af() == AF_INET ? '1' : '2';
      arg += '|';
      arg += addr.host().toString();
      arg += '|';
      arg += NumberFormatter::format(addr.port());
      arg += '|';
      std::string response;
      int status = sendCommand("EPRT", arg, response);
      if (isPositiveCompletion(status))
            return true;
      else if (isPermanentNegative(status))
            return false;
      else
            throw FTPException("EPRT command failed", response);
}


void FTPClientSession::sendPORT(const SocketAddress& addr)
{
      std::string arg(addr.host().toString());
      for (std::string::iterator it = arg.begin(); it != arg.end(); ++it)
      {
            if (*it == '.') *it = ',';
      }
      arg += ',';
      Poco::UInt16 port = addr.port();
      arg += NumberFormatter::format(port/256);
      arg += ',';
      arg += NumberFormatter::format(port % 256);
      std::string response;
      int status = sendCommand("PORT", arg, response);
      if (!isPositiveCompletion(status)) throw FTPException("PORT command failed", response);
}


bool FTPClientSession::sendEPSV(SocketAddress& addr)
{
      std::string response;
      int status = sendCommand("EPSV", response);
      if (isPositiveCompletion(status))
      {
            parseExtAddress(response, addr);
            return true;
      }
      else if (isPermanentNegative(status))
      {
            return false;
      }
      else throw FTPException("EPSV command failed", response);
}


void FTPClientSession::sendPASV(SocketAddress& addr)
{
      std::string response;
      int status = sendCommand("PASV", response);
      if (!isPositiveCompletion(status)) throw FTPException("PASV command failed", response);
      parseAddress(response, addr);
}


void FTPClientSession::parseAddress(const std::string& str, SocketAddress& addr)
{
      std::string::const_iterator it  = str.begin();
      std::string::const_iterator end = str.end();
      while (it != end && *it != '(') ++it;
      if (it != end) ++it;
      std::string host;
      while (it != end && isdigit(*it)) host += *it++;
      if (it != end && *it == ',') { host += '.'; ++it; }
      while (it != end && isdigit(*it)) host += *it++;
      if (it != end && *it == ',') { host += '.'; ++it; }
      while (it != end && isdigit(*it)) host += *it++;
      if (it != end && *it == ',') { host += '.'; ++it; }
      while (it != end && isdigit(*it)) host += *it++;
      if (it != end && *it == ',') ++it;
      Poco::UInt16 portHi = 0;
      while (it != end && isdigit(*it)) { portHi *= 10; portHi += *it++ - '0'; }
      if (it != end && *it == ',') ++it;
      Poco::UInt16 portLo = 0;
      while (it != end && isdigit(*it)) { portLo *= 10; portLo += *it++ - '0'; }
      addr = SocketAddress(host, portHi*256 + portLo);
}


void FTPClientSession::parseExtAddress(const std::string& str, SocketAddress& addr)
{
      std::string::const_iterator it  = str.begin();
      std::string::const_iterator end = str.end();
      while (it != end && *it != '(') ++it;
      if (it != end) ++it;
      char delim = '|';
      if (it != end) delim = *it++;
      if (it != end && *it == delim) ++it;
      if (it != end && *it == delim) ++it;
      Poco::UInt16 port = 0;
      while (it != end && isdigit(*it)) { port *= 10; port += *it++ - '0'; }  
      addr = SocketAddress(_controlSocket.peerAddress().host(), port);  
}


void FTPClientSession::endTransfer()
{
      if (_pDataStream)
      {
            delete _pDataStream;
            _pDataStream = 0;
            std::string response;
            int status = _controlSocket.receiveStatusMessage(response);
            if (!isPositiveCompletion(status)) throw FTPException("Data transfer failed", response);
      }
}


} } // namespace Poco::Net

Generated by  Doxygen 1.6.0   Back to index