28 #include <SFML/Network/Ftp.hpp>
29 #include <SFML/Network/IPAddress.hpp>
64 void Send(
const std::vector<char>& Data);
69 void Receive(std::vector<char>& Data);
98 return myStatus < 400;
129 std::string::size_type Begin = Resp.
GetMessage().find(
'"', 0);
130 std::string::size_type End = Resp.
GetMessage().find(
'"', Begin + 1);
131 myDirectory = Resp.
GetMessage().substr(Begin + 1, End - Begin - 1);
154 std::string Paths(Data.begin(), Data.end());
155 std::string::size_type LastPos = 0;
156 for (std::string::size_type Pos = Paths.find(
"\r\n"); Pos != std::string::npos; Pos = Paths.find(
"\r\n", LastPos))
158 myFilenames.push_back(Paths.substr(LastPos, Pos - LastPos));
170 return myFilenames.size();
179 return myFilenames[Index];
198 if (myCommandSocket.
Connect(Port, Server, Timeout) != Socket::Done)
202 return GetResponse();
211 return Login(
"anonymous",
"user@sfml-dev.org");
220 Response Resp = SendCommand(
"USER", UserName);
222 Resp = SendCommand(
"PASS", Password);
234 Response Resp = SendCommand(
"QUIT");
236 myCommandSocket.
Close();
247 return SendCommand(
"NOOP");
267 std::vector<char> DirData;
273 Resp = SendCommand(
"NLST", Directory);
280 Resp = GetResponse();
293 return SendCommand(
"CWD", Directory);
302 return SendCommand(
"CDUP");
311 return SendCommand(
"MKD", Name);
320 return SendCommand(
"RMD", Name);
329 Response Resp = SendCommand(
"RNFR", File);
331 Resp = SendCommand(
"RNTO", NewName);
342 return SendCommand(
"DELE", Name);
357 Resp = SendCommand(
"RETR", DistantFile);
361 std::vector<char> FileData;
365 Resp = GetResponse();
369 std::string Filename = DistantFile;
370 std::string::size_type Pos = Filename.find_last_of(
"/\\");
371 if (Pos != std::string::npos)
372 Filename = Filename.substr(Pos + 1);
375 std::string Path = DestPath;
376 if (!Path.empty() && (Path[Path.size() - 1] !=
'\\') && (Path[Path.size() - 1] !=
'/'))
380 std::ofstream File((Path + Filename).c_str(), std::ios_base::binary);
383 if (!FileData.empty())
384 File.write(&FileData[0], static_cast<std::streamsize>(FileData.size()));
399 std::ifstream File(LocalFile.c_str(), std::ios_base::binary);
402 File.seekg(0, std::ios::end);
403 std::size_t Length = File.tellg();
404 File.seekg(0, std::ios::beg);
405 std::vector<char> FileData(Length);
407 File.read(&FileData[0], static_cast<std::streamsize>(Length));
410 std::string Filename = LocalFile;
411 std::string::size_type Pos = Filename.find_last_of(
"/\\");
412 if (Pos != std::string::npos)
413 Filename = Filename.substr(Pos + 1);
416 std::string Path = DestPath;
417 if (!Path.empty() && (Path[Path.size() - 1] !=
'\\') && (Path[Path.size() - 1] !=
'/'))
426 Resp = SendCommand(
"STOR", Path + Filename);
433 Resp = GetResponse();
444 Ftp::Response Ftp::SendCommand(
const std::string& Command,
const std::string& Parameter)
447 std::string CommandStr;
449 CommandStr = Command +
" " + Parameter +
"\r\n";
451 CommandStr = Command +
"\r\n";
454 if (myCommandSocket.
Send(CommandStr.c_str(), CommandStr.length()) != sf::Socket::Done)
458 return GetResponse();
466 Ftp::Response Ftp::GetResponse()
471 unsigned int LastCode = 0;
472 bool IsInsideMultiline =
false;
480 if (myCommandSocket.
Receive(Buffer,
sizeof(Buffer), Length) != sf::Socket::Done)
484 std::istringstream In(std::string(Buffer, Length), std::ios_base::binary);
496 if ((Sep ==
'-') && !IsInsideMultiline)
499 IsInsideMultiline =
true;
506 std::getline(In, Message);
509 Message.erase(Message.length() - 1);
510 Message = Sep + Message +
"\n";
516 if ((Sep !=
'-') && ((Code == LastCode) || (LastCode == 0)))
519 IsInsideMultiline =
false;
523 std::getline(In, Line);
526 Line.erase(Line.length() - 1);
529 if (Code == LastCode)
531 std::ostringstream Out;
532 Out << Code << Sep << Line;
533 Message += Out.str();
537 Message = Sep + Line;
541 return Response(static_cast<Response::Status>(Code), Message);
550 std::getline(In, Line);
555 Line.erase(Line.length() - 1);
558 std::ostringstream Out;
559 Out << Code << Sep << Line <<
"\n";
560 Message += Out.str();
565 else if (LastCode != 0)
574 std::getline(In, Line);
579 Line.erase(Line.length() - 1);
582 Message += Line +
"\n";
613 myDataSocket.Close();
627 std::string::size_type begin = Resp.
GetMessage().find_first_of(
"0123456789");
628 if (begin != std::string::npos)
630 sf::Uint8 Data[6] = {0, 0, 0, 0, 0, 0};
631 std::string Str = Resp.
GetMessage().substr(begin);
632 std::size_t Index = 0;
633 for (
int i = 0; i < 6; ++i)
636 while (isdigit(Str[Index]))
638 Data[i] = Data[i] * 10 + (Str[Index] -
'0');
647 unsigned short Port = Data[4] * 256 + Data[5];
649 static_cast<sf::Uint8>(Data[1]),
650 static_cast<sf::Uint8>(Data[2]),
651 static_cast<sf::Uint8>(Data[3]));
654 if (myDataSocket.Connect(Port, Address) == Socket::Done)
666 Resp = myFtp.SendCommand(
"TYPE", ModeStr);
688 std::size_t Received;
689 while (myDataSocket.Receive(Buffer,
sizeof(Buffer), Received) == sf::Socket::Done)
691 std::copy(Buffer, Buffer + Received, std::back_inserter(Data));
695 myDataSocket.Close();
706 myDataSocket.Send(&Data[0], Data.size());
709 myDataSocket.Close();
const std::string & GetFilename(std::size_t Index) const
Get the Index-th filename in the directory.
Status
Enumerate all the valid status codes returned in a FTP response.
DirectoryResponse GetWorkingDirectory()
Get the current working directory.
Response DeleteFile(const std::string &Name)
Remove an existing file.
Ftp::Response Open(Ftp::TransferMode Mode)
Open the data channel using the specified mode and port.
Text mode using EBCDIC encoding.
Connection with server failed.
void Receive(std::vector< char > &Data)
Receive data on the data channel until it is closed.
Response Login()
Log in using anonymous account.
Utility base class to easily declare non-copyable classes.
Response Disconnect()
Close the connection with FTP server.
Response Download(const std::string &DistantFile, const std::string &DestPath, TransferMode Mode=Binary)
Download a file from the server.
const std::string & GetMessage() const
Get the full message contained in the response.
Response Connect(const IPAddress &Server, unsigned short Port=21, float Timeout=0.f)
Connect to the specified FTP server.
Invalid file to upload / download.
This class wraps a FTP response, which is basically :
Status GetStatus() const
Get the response status code.
Specialization of FTP response returning a directory.
~Ftp()
Destructor – close the connection with the server.
Binary mode (file is transfered as a sequence of bytes)
Socket::Status Receive(char *Data, std::size_t MaxSize, std::size_t &SizeReceived)
Receive an array of bytes from the host (must be connected first).
Socket::Status Send(const char *Data, std::size_t Size)
Send an array of bytes to the host (must be connected first)
Response KeepAlive()
Send a null command just to prevent from being disconnected.
Socket::Status Connect(unsigned short Port, const IPAddress &HostAddress, float Timeout=0.f)
Connect to another computer on a specified port.
TransferMode
Enumeration of transfer modes.
Response RenameFile(const std::string &File, const std::string &NewName)
Rename a file.
Response ParentDirectory()
Go to the parent directory of the current one.
Response MakeDirectory(const std::string &Name)
Create a new directory.
Connection with server closed.
ListingResponse(Response Resp, const std::vector< char > &Data)
Default constructor.
ListingResponse GetDirectoryListing(const std::string &Directory="")
Get the contents of the given directory (subdirectories and files)
DirectoryResponse(Response Resp)
Default constructor.
Response(Status Code=InvalidResponse, const std::string &Message="")
Default constructor.
Response ChangeDirectory(const std::string &Directory)
Change the current working directory.
IPAddress provides easy manipulation of IP v4 addresses.
Specialization of FTP response returning a filename lisiting.
const std::string & GetDirectory() const
Get the directory returned in the response.
Response is not a valid FTP one.
This class provides methods for manipulating the FTP protocol (described in RFC 959).
DataChannel(Ftp &Owner)
Constructor.
SocketTCP wraps a socket using TCP protocol to send data safely (but a bit slower) ...
Text mode using ASCII encoding.
Response Upload(const std::string &LocalFile, const std::string &DestPath, TransferMode Mode=Binary)
Upload a file to the server.
bool Close()
Close the socket.
bool IsOk() const
Convenience function to check if the response status code means a success.
Response DeleteDirectory(const std::string &Name)
Remove an existing directory.
~DataChannel()
Destructor.
std::size_t GetCount() const
Get the number of filenames in the listing.
void Send(const std::vector< char > &Data)
Send data on the data channel.