/include/SFML/Network/Ftp.hpp
C++ Header | 616 lines | 119 code | 58 blank | 439 comment | 0 complexity | 4735d91a6d4d6259be87835fcbf98a84 MD5 | raw file
- ////////////////////////////////////////////////////////////
- //
- // SFML - Simple and Fast Multimedia Library
- // Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
- //
- // This software is provided 'as-is', without any express or implied warranty.
- // In no event will the authors be held liable for any damages arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it freely,
- // subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented;
- // you must not claim that you wrote the original software.
- // If you use this software in a product, an acknowledgment
- // in the product documentation would be appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such,
- // and must not be misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source distribution.
- //
- ////////////////////////////////////////////////////////////
- #ifndef SFML_FTP_HPP
- #define SFML_FTP_HPP
- ////////////////////////////////////////////////////////////
- // Headers
- ////////////////////////////////////////////////////////////
- #include <SFML/Network/Export.hpp>
- #include <SFML/Network/TcpSocket.hpp>
- #include <SFML/System/NonCopyable.hpp>
- #include <SFML/System/Time.hpp>
- #include <string>
- #include <vector>
- namespace sf
- {
- class IpAddress;
- ////////////////////////////////////////////////////////////
- /// \brief A FTP client
- ///
- ////////////////////////////////////////////////////////////
- class SFML_NETWORK_API Ftp : NonCopyable
- {
- public:
- ////////////////////////////////////////////////////////////
- /// \brief Enumeration of transfer modes
- ///
- ////////////////////////////////////////////////////////////
- enum TransferMode
- {
- Binary, //!< Binary mode (file is transfered as a sequence of bytes)
- Ascii, //!< Text mode using ASCII encoding
- Ebcdic //!< Text mode using EBCDIC encoding
- };
- ////////////////////////////////////////////////////////////
- /// \brief Define a FTP response
- ///
- ////////////////////////////////////////////////////////////
- class SFML_NETWORK_API Response
- {
- public:
- ////////////////////////////////////////////////////////////
- /// \brief Status codes possibly returned by a FTP response
- ///
- ////////////////////////////////////////////////////////////
- enum Status
- {
- // 1xx: the requested action is being initiated,
- // expect another reply before proceeding with a new command
- RestartMarkerReply = 110, //!< Restart marker reply
- ServiceReadySoon = 120, //!< Service ready in N minutes
- DataConnectionAlreadyOpened = 125, //!< Data connection already opened, transfer starting
- OpeningDataConnection = 150, //!< File status ok, about to open data connection
- // 2xx: the requested action has been successfully completed
- Ok = 200, //!< Command ok
- PointlessCommand = 202, //!< Command not implemented
- SystemStatus = 211, //!< System status, or system help reply
- DirectoryStatus = 212, //!< Directory status
- FileStatus = 213, //!< File status
- HelpMessage = 214, //!< Help message
- SystemType = 215, //!< NAME system type, where NAME is an official system name from the list in the Assigned Numbers document
- ServiceReady = 220, //!< Service ready for new user
- ClosingConnection = 221, //!< Service closing control connection
- DataConnectionOpened = 225, //!< Data connection open, no transfer in progress
- ClosingDataConnection = 226, //!< Closing data connection, requested file action successful
- EnteringPassiveMode = 227, //!< Entering passive mode
- LoggedIn = 230, //!< User logged in, proceed. Logged out if appropriate
- FileActionOk = 250, //!< Requested file action ok
- DirectoryOk = 257, //!< PATHNAME created
- // 3xx: the command has been accepted, but the requested action
- // is dormant, pending receipt of further information
- NeedPassword = 331, //!< User name ok, need password
- NeedAccountToLogIn = 332, //!< Need account for login
- NeedInformation = 350, //!< Requested file action pending further information
- // 4xx: the command was not accepted and the requested action did not take place,
- // but the error condition is temporary and the action may be requested again
- ServiceUnavailable = 421, //!< Service not available, closing control connection
- DataConnectionUnavailable = 425, //!< Can't open data connection
- TransferAborted = 426, //!< Connection closed, transfer aborted
- FileActionAborted = 450, //!< Requested file action not taken
- LocalError = 451, //!< Requested action aborted, local error in processing
- InsufficientStorageSpace = 452, //!< Requested action not taken; insufficient storage space in system, file unavailable
- // 5xx: the command was not accepted and
- // the requested action did not take place
- CommandUnknown = 500, //!< Syntax error, command unrecognized
- ParametersUnknown = 501, //!< Syntax error in parameters or arguments
- CommandNotImplemented = 502, //!< Command not implemented
- BadCommandSequence = 503, //!< Bad sequence of commands
- ParameterNotImplemented = 504, //!< Command not implemented for that parameter
- NotLoggedIn = 530, //!< Not logged in
- NeedAccountToStore = 532, //!< Need account for storing files
- FileUnavailable = 550, //!< Requested action not taken, file unavailable
- PageTypeUnknown = 551, //!< Requested action aborted, page type unknown
- NotEnoughMemory = 552, //!< Requested file action aborted, exceeded storage allocation
- FilenameNotAllowed = 553, //!< Requested action not taken, file name not allowed
- // 10xx: SFML custom codes
- InvalidResponse = 1000, //!< Not part of the FTP standard, generated by SFML when a received response cannot be parsed
- ConnectionFailed = 1001, //!< Not part of the FTP standard, generated by SFML when the low-level socket connection with the server fails
- ConnectionClosed = 1002, //!< Not part of the FTP standard, generated by SFML when the low-level socket connection is unexpectedly closed
- InvalidFile = 1003 //!< Not part of the FTP standard, generated by SFML when a local file cannot be read or written
- };
- ////////////////////////////////////////////////////////////
- /// \brief Default constructor
- ///
- /// This constructor is used by the FTP client to build
- /// the response.
- ///
- /// \param code Response status code
- /// \param message Response message
- ///
- ////////////////////////////////////////////////////////////
- explicit Response(Status code = InvalidResponse, const std::string& message = "");
- ////////////////////////////////////////////////////////////
- /// \brief Check if the status code means a success
- ///
- /// This function is defined for convenience, it is
- /// equivalent to testing if the status code is < 400.
- ///
- /// \return True if the status is a success, false if it is a failure
- ///
- ////////////////////////////////////////////////////////////
- bool isOk() const;
- ////////////////////////////////////////////////////////////
- /// \brief Get the status code of the response
- ///
- /// \return Status code
- ///
- ////////////////////////////////////////////////////////////
- Status getStatus() const;
- ////////////////////////////////////////////////////////////
- /// \brief Get the full message contained in the response
- ///
- /// \return The response message
- ///
- ////////////////////////////////////////////////////////////
- const std::string& getMessage() const;
- private:
- ////////////////////////////////////////////////////////////
- // Member data
- ////////////////////////////////////////////////////////////
- Status m_status; //!< Status code returned from the server
- std::string m_message; //!< Last message received from the server
- };
- ////////////////////////////////////////////////////////////
- /// \brief Specialization of FTP response returning a directory
- ///
- ////////////////////////////////////////////////////////////
- class SFML_NETWORK_API DirectoryResponse : public Response
- {
- public:
- ////////////////////////////////////////////////////////////
- /// \brief Default constructor
- ///
- /// \param response Source response
- ///
- ////////////////////////////////////////////////////////////
- DirectoryResponse(const Response& response);
- ////////////////////////////////////////////////////////////
- /// \brief Get the directory returned in the response
- ///
- /// \return Directory name
- ///
- ////////////////////////////////////////////////////////////
- const std::string& getDirectory() const;
- private:
- ////////////////////////////////////////////////////////////
- // Member data
- ////////////////////////////////////////////////////////////
- std::string m_directory; //!< Directory extracted from the response message
- };
- ////////////////////////////////////////////////////////////
- /// \brief Specialization of FTP response returning a
- /// filename listing
- ////////////////////////////////////////////////////////////
- class SFML_NETWORK_API ListingResponse : public Response
- {
- public:
- ////////////////////////////////////////////////////////////
- /// \brief Default constructor
- ///
- /// \param response Source response
- /// \param data Data containing the raw listing
- ///
- ////////////////////////////////////////////////////////////
- ListingResponse(const Response& response, const std::string& data);
- ////////////////////////////////////////////////////////////
- /// \brief Return the array of directory/file names
- ///
- /// \return Array containing the requested listing
- ///
- ////////////////////////////////////////////////////////////
- const std::vector<std::string>& getListing() const;
- private:
- ////////////////////////////////////////////////////////////
- // Member data
- ////////////////////////////////////////////////////////////
- std::vector<std::string> m_listing; //!< Directory/file names extracted from the data
- };
- ////////////////////////////////////////////////////////////
- /// \brief Destructor
- ///
- /// Automatically closes the connection with the server if
- /// it is still opened.
- ///
- ////////////////////////////////////////////////////////////
- ~Ftp();
- ////////////////////////////////////////////////////////////
- /// \brief Connect to the specified FTP server
- ///
- /// The port has a default value of 21, which is the standard
- /// port used by the FTP protocol. You shouldn't use a different
- /// value, unless you really know what you do.
- /// This function tries to connect to the server so it may take
- /// a while to complete, especially if the server is not
- /// reachable. To avoid blocking your application for too long,
- /// you can use a timeout. The default value, Time::Zero, means that the
- /// system timeout will be used (which is usually pretty long).
- ///
- /// \param server Name or address of the FTP server to connect to
- /// \param port Port used for the connection
- /// \param timeout Maximum time to wait
- ///
- /// \return Server response to the request
- ///
- /// \see disconnect
- ///
- ////////////////////////////////////////////////////////////
- Response connect(const IpAddress& server, unsigned short port = 21, Time timeout = Time::Zero);
- ////////////////////////////////////////////////////////////
- /// \brief Close the connection with the server
- ///
- /// \return Server response to the request
- ///
- /// \see connect
- ///
- ////////////////////////////////////////////////////////////
- Response disconnect();
- ////////////////////////////////////////////////////////////
- /// \brief Log in using an anonymous account
- ///
- /// Logging in is mandatory after connecting to the server.
- /// Users that are not logged in cannot perform any operation.
- ///
- /// \return Server response to the request
- ///
- ////////////////////////////////////////////////////////////
- Response login();
- ////////////////////////////////////////////////////////////
- /// \brief Log in using a username and a password
- ///
- /// Logging in is mandatory after connecting to the server.
- /// Users that are not logged in cannot perform any operation.
- ///
- /// \param name User name
- /// \param password Password
- ///
- /// \return Server response to the request
- ///
- ////////////////////////////////////////////////////////////
- Response login(const std::string& name, const std::string& password);
- ////////////////////////////////////////////////////////////
- /// \brief Send a null command to keep the connection alive
- ///
- /// This command is useful because the server may close the
- /// connection automatically if no command is sent.
- ///
- /// \return Server response to the request
- ///
- ////////////////////////////////////////////////////////////
- Response keepAlive();
- ////////////////////////////////////////////////////////////
- /// \brief Get the current working directory
- ///
- /// The working directory is the root path for subsequent
- /// operations involving directories and/or filenames.
- ///
- /// \return Server response to the request
- ///
- /// \see getDirectoryListing, changeDirectory, parentDirectory
- ///
- ////////////////////////////////////////////////////////////
- DirectoryResponse getWorkingDirectory();
- ////////////////////////////////////////////////////////////
- /// \brief Get the contents of the given directory
- ///
- /// This function retrieves the sub-directories and files
- /// contained in the given directory. It is not recursive.
- /// The \a directory parameter is relative to the current
- /// working directory.
- ///
- /// \param directory Directory to list
- ///
- /// \return Server response to the request
- ///
- /// \see getWorkingDirectory, changeDirectory, parentDirectory
- ///
- ////////////////////////////////////////////////////////////
- ListingResponse getDirectoryListing(const std::string& directory = "");
- ////////////////////////////////////////////////////////////
- /// \brief Change the current working directory
- ///
- /// The new directory must be relative to the current one.
- ///
- /// \param directory New working directory
- ///
- /// \return Server response to the request
- ///
- /// \see getWorkingDirectory, getDirectoryListing, parentDirectory
- ///
- ////////////////////////////////////////////////////////////
- Response changeDirectory(const std::string& directory);
- ////////////////////////////////////////////////////////////
- /// \brief Go to the parent directory of the current one
- ///
- /// \return Server response to the request
- ///
- /// \see getWorkingDirectory, getDirectoryListing, changeDirectory
- ///
- ////////////////////////////////////////////////////////////
- Response parentDirectory();
- ////////////////////////////////////////////////////////////
- /// \brief Create a new directory
- ///
- /// The new directory is created as a child of the current
- /// working directory.
- ///
- /// \param name Name of the directory to create
- ///
- /// \return Server response to the request
- ///
- /// \see deleteDirectory
- ///
- ////////////////////////////////////////////////////////////
- Response createDirectory(const std::string& name);
- ////////////////////////////////////////////////////////////
- /// \brief Remove an existing directory
- ///
- /// The directory to remove must be relative to the
- /// current working directory.
- /// Use this function with caution, the directory will
- /// be removed permanently!
- ///
- /// \param name Name of the directory to remove
- ///
- /// \return Server response to the request
- ///
- /// \see createDirectory
- ///
- ////////////////////////////////////////////////////////////
- Response deleteDirectory(const std::string& name);
- ////////////////////////////////////////////////////////////
- /// \brief Rename an existing file
- ///
- /// The filenames must be relative to the current working
- /// directory.
- ///
- /// \param file File to rename
- /// \param newName New name of the file
- ///
- /// \return Server response to the request
- ///
- /// \see deleteFile
- ///
- ////////////////////////////////////////////////////////////
- Response renameFile(const std::string& file, const std::string& newName);
- ////////////////////////////////////////////////////////////
- /// \brief Remove an existing file
- ///
- /// The file name must be relative to the current working
- /// directory.
- /// Use this function with caution, the file will be
- /// removed permanently!
- ///
- /// \param name File to remove
- ///
- /// \return Server response to the request
- ///
- /// \see renameFile
- ///
- ////////////////////////////////////////////////////////////
- Response deleteFile(const std::string& name);
- ////////////////////////////////////////////////////////////
- /// \brief Download a file from the server
- ///
- /// The filename of the distant file is relative to the
- /// current working directory of the server, and the local
- /// destination path is relative to the current directory
- /// of your application.
- /// If a file with the same filename as the distant file
- /// already exists in the local destination path, it will
- /// be overwritten.
- ///
- /// \param remoteFile Filename of the distant file to download
- /// \param localPath The directory in which to put the file on the local computer
- /// \param mode Transfer mode
- ///
- /// \return Server response to the request
- ///
- /// \see upload
- ///
- ////////////////////////////////////////////////////////////
- Response download(const std::string& remoteFile, const std::string& localPath, TransferMode mode = Binary);
- ////////////////////////////////////////////////////////////
- /// \brief Upload a file to the server
- ///
- /// The name of the local file is relative to the current
- /// working directory of your application, and the
- /// remote path is relative to the current directory of the
- /// FTP server.
- ///
- /// The append parameter controls whether the remote file is
- /// appended to or overwritten if it already exists.
- ///
- /// \param localFile Path of the local file to upload
- /// \param remotePath The directory in which to put the file on the server
- /// \param mode Transfer mode
- /// \param append Pass true to append to or false to overwrite the remote file if it already exists
- ///
- /// \return Server response to the request
- ///
- /// \see download
- ///
- ////////////////////////////////////////////////////////////
- Response upload(const std::string& localFile, const std::string& remotePath, TransferMode mode = Binary, bool append = false);
- ////////////////////////////////////////////////////////////
- /// \brief Send a command to the FTP server
- ///
- /// While the most often used commands are provided as member
- /// functions in the sf::Ftp class, this method can be used
- /// to send any FTP command to the server. If the command
- /// requires one or more parameters, they can be specified
- /// in \a parameter. If the server returns information, you
- /// can extract it from the response using Response::getMessage().
- ///
- /// \param command Command to send
- /// \param parameter Command parameter
- ///
- /// \return Server response to the request
- ///
- ////////////////////////////////////////////////////////////
- Response sendCommand(const std::string& command, const std::string& parameter = "");
- private:
- ////////////////////////////////////////////////////////////
- /// \brief Receive a response from the server
- ///
- /// This function must be called after each call to
- /// sendCommand that expects a response.
- ///
- /// \return Server response to the request
- ///
- ////////////////////////////////////////////////////////////
- Response getResponse();
- ////////////////////////////////////////////////////////////
- /// \brief Utility class for exchanging datas with the server
- /// on the data channel
- ///
- ////////////////////////////////////////////////////////////
- class DataChannel;
- friend class DataChannel;
- ////////////////////////////////////////////////////////////
- // Member data
- ////////////////////////////////////////////////////////////
- TcpSocket m_commandSocket; //!< Socket holding the control connection with the server
- std::string m_receiveBuffer; //!< Received command data that is yet to be processed
- };
- } // namespace sf
- #endif // SFML_FTP_HPP
- ////////////////////////////////////////////////////////////
- /// \class sf::Ftp
- /// \ingroup network
- ///
- /// sf::Ftp is a very simple FTP client that allows you
- /// to communicate with a FTP server. The FTP protocol allows
- /// you to manipulate a remote file system (list files,
- /// upload, download, create, remove, ...).
- ///
- /// Using the FTP client consists of 4 parts:
- /// \li Connecting to the FTP server
- /// \li Logging in (either as a registered user or anonymously)
- /// \li Sending commands to the server
- /// \li Disconnecting (this part can be done implicitly by the destructor)
- ///
- /// Every command returns a FTP response, which contains the
- /// status code as well as a message from the server. Some
- /// commands such as getWorkingDirectory() and getDirectoryListing()
- /// return additional data, and use a class derived from
- /// sf::Ftp::Response to provide this data. The most often used
- /// commands are directly provided as member functions, but it is
- /// also possible to use specific commands with the sendCommand() function.
- ///
- /// Note that response statuses >= 1000 are not part of the FTP standard,
- /// they are generated by SFML when an internal error occurs.
- ///
- /// All commands, especially upload and download, may take some
- /// time to complete. This is important to know if you don't want
- /// to block your application while the server is completing
- /// the task.
- ///
- /// Usage example:
- /// \code
- /// // Create a new FTP client
- /// sf::Ftp ftp;
- ///
- /// // Connect to the server
- /// sf::Ftp::Response response = ftp.connect("ftp://ftp.myserver.com");
- /// if (response.isOk())
- /// std::cout << "Connected" << std::endl;
- ///
- /// // Log in
- /// response = ftp.login("laurent", "dF6Zm89D");
- /// if (response.isOk())
- /// std::cout << "Logged in" << std::endl;
- ///
- /// // Print the working directory
- /// sf::Ftp::DirectoryResponse directory = ftp.getWorkingDirectory();
- /// if (directory.isOk())
- /// std::cout << "Working directory: " << directory.getDirectory() << std::endl;
- ///
- /// // Create a new directory
- /// response = ftp.createDirectory("files");
- /// if (response.isOk())
- /// std::cout << "Created new directory" << std::endl;
- ///
- /// // Upload a file to this new directory
- /// response = ftp.upload("local-path/file.txt", "files", sf::Ftp::Ascii);
- /// if (response.isOk())
- /// std::cout << "File uploaded" << std::endl;
- ///
- /// // Send specific commands (here: FEAT to list supported FTP features)
- /// response = ftp.sendCommand("FEAT");
- /// if (response.isOk())
- /// std::cout << "Feature list:\n" << response.getMessage() << std::endl;
- ///
- /// // Disconnect from the server (optional)
- /// ftp.disconnect();
- /// \endcode
- ///
- ////////////////////////////////////////////////////////////