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();
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.
Status GetStatus() const
Get the response status code.
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.
Response Connect(const IPAddress &Server, unsigned short Port=21, float Timeout=0.f)
Connect to the specified FTP server.
std::size_t GetCount() const
Get the number of filenames in the listing.
Invalid file to upload / download.
This class wraps a FTP response, which is basically :
Specialization of FTP response returning a directory.
bool IsOk() const
Convenience function to check if the response status code means a success.
~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.
const std::string & GetFilename(std::size_t Index) const
Get the Index-th filename in the directory.
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.
Response is not a valid FTP one.
This class provides methods for manipulating the FTP protocol (described in RFC 959).
const std::string & GetDirectory() const
Get the directory returned in the response.
DataChannel(Ftp &Owner)
Constructor.
SocketTCP wraps a socket using TCP protocol to send data safely (but a bit slower) ...
Text mode using ASCII encoding.
const std::string & GetMessage() const
Get the full message contained in the response.
Response Upload(const std::string &LocalFile, const std::string &DestPath, TransferMode Mode=Binary)
Upload a file to the server.
bool Close()
Close the socket.
Response DeleteDirectory(const std::string &Name)
Remove an existing directory.
~DataChannel()
Destructor.
void Send(const std::vector< char > &Data)
Send data on the data channel.