00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00024
00026
00028 #include <SFML/AdvancedNetwork/FTP.hpp>
00029 #include <algorithm>
00030 #include <fstream>
00031 #include <iostream>
00032 #include <iterator>
00033 #include <sstream>
00034
00035
00039 sfFTP::sfFTP(Listener* FTPListener) :
00040 myListener(FTPListener)
00041 {
00042
00043 }
00044
00045
00049 sfFTP::~sfFTP()
00050 {
00051 Disconnect();
00052 }
00053
00054
00058 bool sfFTP::Connect(const sfIPAddress& Server, unsigned int Port)
00059 {
00060
00061 if (!Server.IsValid())
00062 {
00063 std::cerr << "FTP server address is not valid (" << Server << ")" << std::endl;
00064 return false;
00065 }
00066
00067
00068 if (!myCommandSocket.Connect(Port, Server))
00069 {
00070 std::cerr << "Failed to connect to FTP server " << Server << std::endl;
00071 return false;
00072 }
00073
00074
00075 return GetResponse();
00076 }
00077
00078
00082 bool sfFTP::Login(const std::string& UserName, const std::string& Password)
00083 {
00084 return SendCommand("USER", UserName) &&
00085 SendCommand("PASS", Password);
00086 }
00087
00088
00092 bool sfFTP::Disconnect()
00093 {
00094
00095 if (!SendCommand("QUIT"))
00096 return false;
00097
00098
00099 return myCommandSocket.Close();
00100 }
00101
00102
00106 bool sfFTP::KeepAlive()
00107 {
00108 return SendCommand("NOOP");
00109 }
00110
00111
00115 bool sfFTP::GetWorkingDirectory(std::string& Directory)
00116 {
00117
00118 Directory = "";
00119
00120
00121 if (!SendCommand("PWD"))
00122 return false;
00123
00124
00125 std::string::size_type Begin = myLastMessage.find('"', 0);
00126 std::string::size_type End = myLastMessage.find('"', Begin + 1);
00127 Directory = myLastMessage.substr(Begin + 1, End - Begin - 1);
00128
00129 return true;
00130 }
00131
00132
00137 bool sfFTP::GetDirectoryListing(std::vector<std::string>& Listing, const std::string& Directory)
00138 {
00139
00140 Listing.clear();
00141
00142
00143 DataChannel Data(*this);
00144 if (!Data.Open(Ascii))
00145 return false;
00146
00147
00148 if (!SendCommand("NLST", Directory))
00149 return false;
00150
00151
00152 std::vector<char> DirData;
00153 Data.Receive(DirData);
00154
00155
00156 if (!GetResponse())
00157 return false;
00158
00159
00160 std::string Paths(DirData.begin(), DirData.end());
00161 std::string::size_type LastPos = 0;
00162 for (std::string::size_type Pos = Paths.find("\r\n"); Pos != std::string::npos; Pos = Paths.find("\r\n", LastPos))
00163 {
00164 Listing.push_back(Paths.substr(LastPos, Pos - LastPos));
00165 LastPos = Pos + 2;
00166 }
00167
00168
00169 std::sort(Listing.begin(), Listing.end());
00170
00171 return true;
00172 }
00173
00174
00178 bool sfFTP::ChangeDirectory(const std::string& Directory)
00179 {
00180 return SendCommand("CWD", Directory);
00181 }
00182
00183
00187 bool sfFTP::ParentDirectory()
00188 {
00189 return SendCommand("CDUP");
00190 }
00191
00192
00196 bool sfFTP::MakeDirectory(const std::string& Name)
00197 {
00198 return SendCommand("MKD", Name);
00199 }
00200
00201
00205 bool sfFTP::DeleteDirectory(const std::string& Name)
00206 {
00207 return SendCommand("RMD", Name);
00208 }
00209
00210
00214 bool sfFTP::RenameFile(const std::string& File, const std::string& NewName)
00215 {
00216 return SendCommand("RNFR", File) &&
00217 SendCommand("RNTO", NewName);
00218 }
00219
00220
00224 bool sfFTP::RemoveFile(const std::string& Name)
00225 {
00226 return SendCommand("DELE", Name);
00227 }
00228
00229
00233 bool sfFTP::Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode)
00234 {
00235
00236 DataChannel Data(*this);
00237 if (!Data.Open(Mode))
00238 return false;
00239
00240
00241 if (!SendCommand("RETR", DistantFile))
00242 return false;
00243
00244
00245 std::vector<char> FileData;
00246 Data.Receive(FileData);
00247
00248
00249 if (!GetResponse())
00250 return false;
00251
00252
00253 std::string Filename = DistantFile;
00254 std::string::size_type Pos = Filename.find_last_of("/\\");
00255 if (Pos != std::string::npos)
00256 Filename = Filename.substr(Pos + 1);
00257
00258
00259 std::string Path = DestPath;
00260 if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
00261 Path += "/";
00262
00263
00264 std::ofstream File((Path + Filename).c_str(), std::ios_base::binary);
00265 File.write(&FileData[0], static_cast<std::streamsize>(FileData.size()));
00266
00267 return true;
00268 }
00269
00270
00274 bool sfFTP::Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode)
00275 {
00276
00277 std::ifstream File(LocalFile.c_str(), std::ios_base::binary);
00278 File.seekg(0, std::ios::end);
00279 std::size_t Length = File.tellg();
00280 File.seekg(0, std::ios::beg);
00281 std::vector<char> FileData(Length);
00282 File.read(&FileData[0], static_cast<std::streamsize>(Length));
00283
00284
00285 std::string Filename = LocalFile;
00286 std::string::size_type Pos = Filename.find_last_of("/\\");
00287 if (Pos != std::string::npos)
00288 Filename = Filename.substr(Pos + 1);
00289
00290
00291 std::string Path = DestPath;
00292 if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
00293 Path += "/";
00294
00295
00296 DataChannel Data(*this);
00297 if (!Data.Open(Mode))
00298 return false;
00299
00300
00301 if (!SendCommand("STOR", Path + Filename))
00302 return false;
00303
00304
00305 Data.Send(FileData);
00306
00307
00308 if (!GetResponse())
00309 return false;
00310
00311 return true;
00312 }
00313
00314
00318 bool sfFTP::SendCommand(const std::string& Command, const std::string& Parameter)
00319 {
00320
00321 std::string CommandStr;
00322 if (Parameter != "")
00323 CommandStr = Command + " " + Parameter + "\r\n";
00324 else
00325 CommandStr = Command + "\r\n";
00326
00327
00328 if (!myCommandSocket.Send(CommandStr.c_str(), CommandStr.length()))
00329 {
00330 std::cerr << "FTP connection closed " << std::endl;
00331 return false;
00332 }
00333
00334
00335 return GetResponse();
00336 }
00337
00338
00343 bool sfFTP::GetResponse()
00344 {
00345
00346
00347
00348 unsigned int LastCode = 0;
00349 bool IsInsideMultiline = false;
00350
00351 while (true)
00352 {
00353
00354 char Buffer[1024];
00355 std::size_t Length;
00356 if (!myCommandSocket.Receive(Buffer, sizeof(Buffer), Length))
00357 {
00358 std::cerr << "FTP connection closed " << std::endl;
00359 return false;
00360 }
00361
00362
00363 std::istringstream iss(std::string(Buffer, Length), std::ios_base::binary);
00364 while (iss)
00365 {
00366
00367 unsigned int Code;
00368 if (iss >> Code)
00369 {
00370
00371 char Sep;
00372 iss.get(Sep);
00373
00374
00375 if ((Sep == '-') && !IsInsideMultiline)
00376 {
00377
00378 IsInsideMultiline = true;
00379
00380
00381 if (LastCode == 0)
00382 LastCode = Code;
00383
00384
00385 std::getline(iss, myLastMessage);
00386
00387
00388 myLastMessage.erase(myLastMessage.length() - 1);
00389 myLastMessage = Sep + myLastMessage + "\n";
00390 }
00391 else
00392 {
00393
00394
00395 if ((Sep != '-') && ((Code == LastCode) || (LastCode == 0)))
00396 {
00397
00398 IsInsideMultiline = false;
00399
00400
00401 std::string Line;
00402 std::getline(iss, Line);
00403
00404
00405 Line.erase(Line.length() - 1);
00406
00407
00408 if (Code == LastCode)
00409 {
00410 std::ostringstream oss;
00411 oss << Code << Sep << Line;
00412 myLastMessage += oss.str();
00413 }
00414 else
00415 {
00416 myLastMessage = Sep + Line;
00417 }
00418
00419
00420 if (myListener)
00421 myListener->OnResponse(Code, myLastMessage);
00422
00423
00424 return Code < 400;
00425 }
00426 else
00427 {
00428
00429
00430
00431
00432 std::string Line;
00433 std::getline(iss, Line);
00434
00435 if (!Line.empty())
00436 {
00437
00438 Line.erase(Line.length() - 1);
00439
00440
00441 std::ostringstream oss;
00442 oss << Code << Sep << Line << "\n";
00443 myLastMessage += oss.str();
00444 }
00445 }
00446 }
00447 }
00448 else if (LastCode != 0)
00449 {
00450
00451
00452
00453 iss.clear();
00454
00455
00456 std::string Line;
00457 std::getline(iss, Line);
00458
00459 if (!Line.empty())
00460 {
00461
00462 Line.erase(Line.length() - 1);
00463
00464
00465 myLastMessage += Line + "\n";
00466 }
00467 }
00468 else
00469 {
00470
00471 std::cerr << "Invalid response from the FTP server" << std::endl;
00472 return false;
00473 }
00474 }
00475 }
00476
00477 return false;
00478 }
00479
00480
00484 sfFTP::DataChannel::DataChannel(sfFTP& FTP) :
00485 myFTP(FTP)
00486 {
00487
00488 }
00489
00490
00494 sfFTP::DataChannel::~DataChannel()
00495 {
00496
00497 myDataSocket.Close();
00498 }
00499
00500
00504 bool sfFTP::DataChannel::Open(sfFTP::TransferMode Mode, unsigned short Port)
00505 {
00506
00507 if (!myDataSocket.Listen(Port))
00508 return false;
00509
00510
00511 unsigned short P1 = Port / 256;
00512 unsigned short P2 = Port % 256;
00513 sfIPAddress Address = sfIPAddress::GetLocalAddress();
00514 std::ostringstream oss;
00515 oss << Address << "." << P1 << "." << P2;
00516 std::string Parameter = oss.str();
00517 std::replace(Parameter.begin(), Parameter.end(), '.', ',');
00518
00519
00520 if (!myFTP.SendCommand("PORT", Parameter))
00521 return false;
00522
00523
00524 std::string ModeStr;
00525 switch (Mode)
00526 {
00527 case sfFTP::Binary : ModeStr = "I"; break;
00528 case sfFTP::Ascii : ModeStr = "A"; break;
00529 case sfFTP::Ebcdic : ModeStr = "E"; break;
00530 }
00531
00532
00533 if (!myFTP.SendCommand("TYPE", ModeStr))
00534 return false;
00535
00536 return true;
00537 }
00538
00539
00543 void sfFTP::DataChannel::Receive(std::vector<char>& Data)
00544 {
00545
00546 sfSocketTCP TransferSocket = myDataSocket.Accept();
00547
00548
00549 Data.clear();
00550 char Buffer[1024];
00551 std::size_t Received;
00552 while (TransferSocket.Receive(Buffer, sizeof(Buffer), Received))
00553 {
00554 std::copy(Buffer, Buffer + Received, std::back_inserter(Data));
00555 }
00556
00557
00558 TransferSocket.Close();
00559 }
00560
00561
00565 void sfFTP::DataChannel::Send(const std::vector<char>& Data)
00566 {
00567
00568 sfSocketTCP TransferSocket = myDataSocket.Accept();
00569
00570
00571 TransferSocket.Send(&Data[0], Data.size());
00572
00573
00574 TransferSocket.Close();
00575 }