// // FTPClientSession.h // // Library: Net // Package: FTP // Module: FTPClientSession // // Definition of the FTPClientSession class. // // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #ifndef Net_FTPClientSession_INCLUDED #define Net_FTPClientSession_INCLUDED #include "Poco/Net/Net.h" #include "Poco/Net/DialogSocket.h" #include "Poco/Timespan.h" #include #include namespace Poco { namespace Net { class SocketStream; class Net_API FTPClientSession /// This class implements an File Transfer Protocol /// (FTP, RFC 959) client. /// /// Most of the features of the FTP protocol, as specified /// in RFC 959, are supported. Not supported are EBCDIC and /// LOCAL data types and format control and structured files. /// /// Also supported are the EPRT and EPSV commands from /// RFC 1738 (FTP Extensions for IPv6 and NAT). /// The client will first attempt to use the EPRT and EPSV /// commands. If the server does not supports these commands, /// the client will fall back to PORT and PASV. { public: enum { FTP_PORT = 21 }; enum FileType { TYPE_TEXT, /// TYPE A (ASCII) TYPE_BINARY /// TYPE I (Image/binary data) }; FTPClientSession(); /// Creates an FTPClientSession. /// /// Passive mode will be used for data transfers. FTPClientSession(const StreamSocket& socket, bool readWelcomeMessage = true); /// Creates an FTPClientSession using the given /// connected socket for the control connection. /// /// Passive mode will be used for data transfers. FTPClientSession(const std::string& host, Poco::UInt16 port = FTP_PORT, const std::string& username = "", const std::string& password = ""); /// Creates an FTPClientSession using a socket connected /// to the given host and port. If username is supplied, /// login is attempted. /// /// Passive mode will be used for data transfers. virtual ~FTPClientSession(); /// Destroys the FTPClientSession. void setTimeout(const Poco::Timespan& timeout); /// Sets the timeout for socket operations. Poco::Timespan getTimeout() const; /// Returns the timeout for socket operations. void setPassive(bool flag, bool useRFC1738 = true); /// Enables (default) or disables FTP passive mode for this session. /// /// If useRFC1738 is true (the default), the RFC 1738 /// EPSV command is used (with a fallback to PASV if EPSV fails) /// for switching to passive mode. The same applies to /// EPRT and PORT for active connections. bool getPassive() const; /// Returns true iff passive mode is enabled for this connection. virtual 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. virtual void login(const std::string& username, const std::string& password); /// Authenticates the user against the FTP server. Must be /// called before any other commands (except QUIT) can be sent. /// /// Sends a USER command followed by a PASS command with the /// respective arguments to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. void logout(); /// Logs out from the server by sending a QUIT command. Any transfer /// that's in progress is ended. The control connection is kept /// open. void close(); /// Sends a QUIT command and closes the connection to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. std::string systemType(); /// Returns the system type of the FTP server. /// /// Sends a SYST command to the server and returns the result. void setFileType(FileType type); /// Sets the file type for transferring files. /// /// Sends a TYPE command with a corresponding argument to the /// server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. FileType getFileType() const; /// Returns the file type for transferring files. void setWorkingDirectory(const std::string& path); /// Changes the current working directory on the server. /// /// Sends a CWD command with the given path as argument to the /// server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. std::string getWorkingDirectory(); /// Returns the current working directory on the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. void cdup(); /// Moves one directory up from the current working directory /// on the server. /// /// Sends a CDUP command to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. void rename(const std::string& oldName, const std::string& newName); /// Renames the file on the server given by oldName to newName. /// /// Sends a RNFR command, followed by a RNTO command to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. void remove(const std::string& path); /// Deletes the file specified by path on the server. /// /// Sends a DELE command with path as argument to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. void createDirectory(const std::string& path); /// Creates a new directory with the given path on the server. /// /// Sends a MKD command with path as argument to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. void removeDirectory(const std::string& path); /// Removes the directory specified by path from the server. /// /// Sends a RMD command with path as argument to the server. /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. std::istream& beginDownload(const std::string& path); /// Starts downloading the file with the given name. /// After all data has been read from the returned stream, /// endDownload() must be called to finish the download. /// /// A stream for reading the file's content is returned. /// The stream is valid until endDownload() is called. /// /// Creates a data connection between the client and the /// server. If passive mode is on, then the server waits for /// a connection request from the client. Otherwise, the /// client waits for a connection request from the server. /// After establishing the data connection, a SocketStream /// for transferring the data is created. /// /// If ASCII transfer mode is selected, the caller is /// responsible for converting the received data to /// the native text file format. /// The InputLineEndingConverter class from the Foundation /// library can be used for that purpose. void endDownload(); /// Must be called to complete a download initiated with /// beginDownload(). std::ostream& beginUpload(const std::string& path); /// Starts uploading the file with the given name. /// After all data has been written to the returned stream, /// endUpload() must be called to finish the upload. /// /// A stream for reading the file's content is returned. /// The stream is valid until endUpload() is called. /// /// Creates a data connection between the client and the /// server. If passive mode is on, then the server waits for /// a connection request from the client. Otherwise, the /// client waits for a connection request from the server. /// After establishing the data connection, a SocketStream /// for transferring the data is created. /// /// If ASCII transfer mode is selected, the caller is /// responsible for converting the data to be sent /// into network (CR-LF line endings) format. /// The OutputLineEndingConverter class from the Foundation /// library can be used for that purpose. void endUpload(); /// Must be called to complete an upload initiated with /// beginUpload(). std::istream& beginList(const std::string& path = "", bool extended = false); /// Starts downloading a directory listing. /// After all data has been read from the returned stream, /// endList() must be called to finish the download. /// /// A stream for reading the directory data is returned. /// The stream is valid until endList() is called. /// /// Optionally, a path to a directory or file can be specified. /// According to the FTP protocol, if a path to a filename is /// given, only information for the specific file is returned. /// If a path to a directory is given, a listing of that directory /// is returned. If no path is given, a listing of the current /// working directory is returned. /// /// If extended is false, only a filenames (one per line) are /// returned. Otherwise, a full directory listing including /// file attributes is returned. The format of this listing /// depends on the FTP server. No attempt is made to interpret /// this data. /// /// Creates a data connection between the client and the /// server. If passive mode is on, then the server waits for /// a connection request from the client. Otherwise, the /// client waits for a connection request from the server. /// After establishing the data connection, a SocketStream /// for transferring the data is created. void endList(); /// Must be called to complete a directory listing download /// initiated with beginList(). void abort(); /// Aborts the download or upload currently in progress. /// /// Sends a TELNET IP/SYNCH sequence, followed by an ABOR /// command to the server. /// /// A separate call to endDownload() or endUpload() is /// not necessary. int sendCommand(const std::string& command, std::string& response); /// Sends the given command verbatim to the server /// and waits for a response. int sendCommand(const std::string& command, const std::string& arg, std::string& response); /// Sends the given command verbatim to the server /// and waits for a response. bool isOpen() const; /// Returns true if the connection with FTP server is opened. bool isLoggedIn() const; /// Returns true if the session is logged in. bool isSecure() const; /// Returns true if the session is FTPS. const std::string& welcomeMessage(); /// Returns the welcome message. protected: virtual void receiveServerReadyReply(); enum StatusClass { FTP_POSITIVE_PRELIMINARY = 1, FTP_POSITIVE_COMPLETION = 2, FTP_POSITIVE_INTERMEDIATE = 3, FTP_TRANSIENT_NEGATIVE = 4, FTP_PERMANENT_NEGATIVE = 5 }; enum { DEFAULT_TIMEOUT = 30000000 // 30 seconds default timeout for socket operations }; static bool isPositivePreliminary(int status); static bool isPositiveCompletion(int status); static bool isPositiveIntermediate(int status); static bool isTransientNegative(int status); static bool isPermanentNegative(int status); std::string extractPath(const std::string& response); virtual StreamSocket establishDataConnection(const std::string& command, const std::string& arg); StreamSocket activeDataConnection(const std::string& command, const std::string& arg); StreamSocket passiveDataConnection(const std::string& command, const std::string& arg); void sendPortCommand(const SocketAddress& addr); SocketAddress sendPassiveCommand(); bool sendEPRT(const SocketAddress& addr); void sendPORT(const SocketAddress& addr); bool sendEPSV(SocketAddress& addr); void sendPASV(SocketAddress& addr); void parseAddress(const std::string& str, SocketAddress& addr); void parseExtAddress(const std::string& str, SocketAddress& addr); void endTransfer(); DialogSocket* _pControlSocket = nullptr; SocketStream* _pDataStream = nullptr; private: FTPClientSession(const FTPClientSession&); FTPClientSession& operator = (const FTPClientSession&); std::string _host; Poco::UInt16 _port = FTP_PORT; bool _passiveMode = true; FileType _fileType = TYPE_BINARY; bool _supports1738 = true; bool _serverReady = false; bool _isLoggedIn = false; Poco::Timespan _timeout = DEFAULT_TIMEOUT; std::string _welcomeMessage; Poco::FastMutex _wmMutex; }; // // inlines // inline bool FTPClientSession::isPositivePreliminary(int status) { return status/100 == FTP_POSITIVE_PRELIMINARY; } inline bool FTPClientSession::isPositiveCompletion(int status) { return status/100 == FTP_POSITIVE_COMPLETION; } inline bool FTPClientSession::isPositiveIntermediate(int status) { return status/100 == FTP_POSITIVE_INTERMEDIATE; } inline bool FTPClientSession::isTransientNegative(int status) { return status/100 == FTP_TRANSIENT_NEGATIVE; } inline bool FTPClientSession::isPermanentNegative(int status) { return status/100 == FTP_PERMANENT_NEGATIVE; } inline bool FTPClientSession::isOpen() const { return _pControlSocket != 0; } inline bool FTPClientSession::isLoggedIn() const { return _isLoggedIn; } inline bool FTPClientSession::isSecure() const { return false; } inline const std::string& FTPClientSession::welcomeMessage() { Poco::FastMutex::ScopedLock lock(_wmMutex); return _welcomeMessage; } } } // namespace Poco::Net #endif // Net_FTPClientSession_INCLUDED