SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
FtpUtils.cpp
Go to the documentation of this file.
1 /**
2  * \file FtpUtils.cpp
3  * \authors Marcus Hudritsch, Michael Goettlicher
4  * \date May 2019
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8 */
9 
10 #ifndef __EMSCRIPTEN__
11 
12 # include <sstream>
13 # include <algorithm>
14 # include <ftplib.h>
15 # include <FtpUtils.h>
16 # include <Utils.h>
17 
18 using namespace std;
19 
20 namespace FtpUtils
21 {
22 //-----------------------------------------------------------------------------
23 //! Uploads the file to the ftp server. Checks if the filename already exists and adds a version number
24 /*!
25  * \param fileDir
26  * \param fileName
27  * \param ftpHost
28  * \param ftpUser
29  * \param ftpPwd
30  * \param ftpDir
31  * \param errorMsg
32  * \return
33  */
34 bool uploadFileLatestVersion(const string& fileDir,
35  const string& fileName,
36  const string& ftpHost,
37  const string& ftpUser,
38  const string& ftpPwd,
39  const string& ftpDir,
40  string& errorMsg)
41 {
42  string fullPathAndFilename = fileDir + fileName;
43  if (!Utils::fileExists(fullPathAndFilename))
44  {
45  errorMsg = "File doesn't exist: " + fullPathAndFilename;
46  return false;
47  }
48 
49  bool success = true;
50  ftplib ftp;
51  // enable active mode
52  ftp.SetConnmode(ftplib::connmode::port);
53 
54  if (ftp.Connect(ftpHost.c_str()))
55  {
56  if (ftp.Login(ftpUser.c_str(), ftpPwd.c_str()))
57  {
58  if (ftp.Chdir(ftpDir.c_str()))
59  {
60  // Get the latest fileName on the ftp
61  string latestFile = getLatestFilename(ftp, fileDir, fileName);
62 
63  // Set the file version
64  int versionNO = 0;
65  if (!latestFile.empty())
66  {
67  versionNO = getVersionInFilename(latestFile);
68  }
69 
70  // Increase the version
71  versionNO++;
72  stringstream versionSS;
73  versionSS << "(" << versionNO << ")";
74 
75  // Build new fileName on ftp with version number
76  string fileWOExt = Utils::getFileNameWOExt(fullPathAndFilename);
77  string newVersionFilename = fileWOExt + versionSS.str() + ".xml";
78 
79  // Upload
80  if (!ftp.Put(fullPathAndFilename.c_str(),
81  newVersionFilename.c_str(),
82  ftplib::transfermode::image))
83  {
84  errorMsg = "*** ERROR: ftp.Put failed. ***\n";
85  success = false;
86  }
87  }
88  else
89  {
90  errorMsg = "*** ERROR: ftp.Chdir failed. ***\n";
91  success = false;
92  }
93  }
94  else
95  {
96  errorMsg = "*** ERROR: ftp.Login failed. ***\n";
97  success = false;
98  }
99  }
100  else
101  {
102  errorMsg = "*** ERROR: ftp.Connect failed. ***\n";
103  success = false;
104  }
105 
106  ftp.Quit();
107  return success;
108 }
109 //-----------------------------------------------------------------------------
110 //! Download the file from the ftp server which has the latest version and store it as fileName locally
111 /*!
112  * \param fileDir
113  * \param fileName
114  * \param ftpHost
115  * \param ftpUser
116  * \param ftpPwd
117  * \param ftpDir
118  * \param errorMsg
119  * \return
120  */
121 bool downloadFileLatestVersion(const string& fileDir,
122  const string& fileName,
123  const string& ftpHost,
124  const string& ftpUser,
125  const string& ftpPwd,
126  const string& ftpDir,
127  string& errorMsg)
128 {
129  bool success = true;
130  ftplib ftp;
131  // enable active mode
132  ftp.SetConnmode(ftplib::connmode::port);
133 
134  if (ftp.Connect(ftpHost.c_str()))
135  {
136  if (ftp.Login(ftpUser.c_str(), ftpPwd.c_str()))
137  {
138  if (ftp.Chdir(ftpDir.c_str()))
139  {
140  // Get the latest fileName on the ftp
141  string fullPathAndFilename = fileDir + fileName;
142  string latestFile = getLatestFilename(ftp, fileDir, fileName);
143  int remoteSize = 0;
144  ftp.Size(latestFile.c_str(),
145  &remoteSize,
146  ftplib::transfermode::image);
147 
148  if (remoteSize > 0)
149  {
150  if (!ftp.Get(fullPathAndFilename.c_str(),
151  latestFile.c_str(),
152  ftplib::transfermode::image))
153  {
154  errorMsg = "*** ERROR: ftp.Get failed. ***\n";
155  success = false;
156  }
157  }
158  else
159  {
160  errorMsg = "*** No file to download ***\n";
161  success = false;
162  }
163  }
164  else
165  {
166  errorMsg = "*** ERROR: ftp.Chdir failed. ***\n";
167  success = false;
168  }
169  }
170  else
171  {
172  errorMsg = "*** ERROR: ftp.Login failed. ***\n";
173  success = false;
174  }
175  }
176  else
177  {
178  errorMsg = "*** ERROR: ftp.Connect failed. ***\n";
179  success = false;
180  }
181 
182  ftp.Quit();
183  return success;
184 }
185 //-----------------------------------------------------------------------------
186 //! Uploads file to the ftp server
187 /*!
188  *
189  * \param fileDir
190  * \param fileName
191  * \param ftpHost
192  * \param ftpUser
193  * \param ftpPwd
194  * \param ftpDir
195  * \param errorMsg
196  * \return
197  */
198 bool uploadFile(const string& fileDir,
199  const string& fileName,
200  const string& ftpHost,
201  const string& ftpUser,
202  const string& ftpPwd,
203  const string& ftpDir,
204  string& errorMsg)
205 {
206  string fullPathAndFilename = fileDir + fileName;
207  if (!Utils::fileExists(fullPathAndFilename))
208  {
209  errorMsg = "File doesn't exist: " + fullPathAndFilename;
210  return false;
211  }
212 
213  bool success = true;
214  ftplib ftp;
215  // enable active mode
216  ftp.SetConnmode(ftplib::connmode::port);
217 
218  if (ftp.Connect(ftpHost.c_str()))
219  {
220  if (ftp.Login(ftpUser.c_str(), ftpPwd.c_str()))
221  {
222  if (ftp.Chdir(ftpDir.c_str()))
223  {
224  // Upload
225  if (!ftp.Put(fullPathAndFilename.c_str(),
226  fileName.c_str(),
227  ftplib::transfermode::image))
228  {
229  errorMsg = "*** ERROR: ftp.Put failed. ***\n";
230  success = false;
231  }
232  }
233  else
234  {
235  errorMsg = "*** ERROR: ftp.Chdir failed. ***\n";
236  success = false;
237  }
238  }
239  else
240  {
241  errorMsg = "*** ERROR: ftp.Login failed. ***\n";
242  success = false;
243  }
244  }
245  else
246  {
247  errorMsg = "*** ERROR: ftp.Connect failed. ***\n";
248  success = false;
249  }
250 
251  ftp.Quit();
252  return success;
253 }
254 //-----------------------------------------------------------------------------
255 //! Download file from the ftp server
256 /*!
257  *
258  * \param fileDir
259  * \param fileName
260  * \param ftpHost
261  * \param ftpUser
262  * \param ftpPwd
263  * \param ftpDir
264  * \param errorMsg
265  * \return
266  */
267 bool downloadFile(const string& fileDir,
268  const string& fileName,
269  const string& ftpHost,
270  const string& ftpUser,
271  const string& ftpPwd,
272  const string& ftpDir,
273  string& errorMsg)
274 {
275  bool success = true;
276  ftplib ftp;
277  // enable active mode
278  ftp.SetConnmode(ftplib::connmode::port);
279 
280  if (ftp.Connect(ftpHost.c_str()))
281  {
282  if (ftp.Login(ftpUser.c_str(), ftpPwd.c_str()))
283  {
284  if (ftp.Chdir(ftpDir.c_str()))
285  {
286  // Get the latest fileName on the ftp
287  string fullPathAndFilename = fileDir + fileName;
288  int remoteSize = 0;
289  ftp.Size(fileName.c_str(),
290  &remoteSize,
291  ftplib::transfermode::image);
292 
293  if (remoteSize > 0)
294  {
295  if (!ftp.Get(fullPathAndFilename.c_str(),
296  fileName.c_str(),
297  ftplib::transfermode::image))
298  {
299  errorMsg = "*** ERROR: ftp.Get failed. ***\n";
300  success = false;
301  }
302  }
303  else
304  {
305  errorMsg = "*** No file to download ***\n";
306  success = false;
307  }
308  }
309  else
310  {
311  errorMsg = "*** ERROR: ftp.Chdir failed. ***\n";
312  success = false;
313  }
314  }
315  else
316  {
317  errorMsg = "*** ERROR: ftp.Login failed. ***\n";
318  success = false;
319  }
320  }
321  else
322  {
323  errorMsg = "*** ERROR: ftp.Connect failed. ***\n";
324  success = false;
325  }
326 
327  ftp.Quit();
328  return success;
329 }
330 //-----------------------------------------------------------------------------
331 /*!
332  *
333  * \param fileDir
334  * \param ftpHost
335  * \param ftpUser
336  * \param ftpPwd
337  * \param ftpDir
338  * \param searchFileTag
339  * \param errorMsg
340  * \return
341  */
342 bool downloadAllFilesFromDir(const string& fileDir,
343  const string& ftpHost,
344  const string& ftpUser,
345  const string& ftpPwd,
346  const string& ftpDir,
347  const string& searchFileTag,
348  string& errorMsg)
349 {
350  bool success = true;
351  ftplib ftp;
352  // enable active mode
353  ftp.SetConnmode(ftplib::connmode::port);
354 
355  if (ftp.Connect(ftpHost.c_str()))
356  {
357  if (ftp.Login(ftpUser.c_str(), ftpPwd.c_str()))
358  {
359  if (ftp.Chdir(ftpDir.c_str()))
360  {
361  // get all names in directory
362  vector<string> retrievedFileNames;
363  if ((success = getAllFileNamesWithTag(ftp,
364  fileDir,
365  searchFileTag,
366  retrievedFileNames,
367  errorMsg)))
368  {
369  for (auto& retrievedFileName : retrievedFileNames)
370  {
371  int remoteSize = 0;
372  ftp.Size(retrievedFileName.c_str(),
373  &remoteSize,
374  ftplib::transfermode::image);
375 
376  if (remoteSize > 0)
377  {
378  string targetFilename = fileDir + retrievedFileName;
379  if (!ftp.Get(targetFilename.c_str(),
380  retrievedFileName.c_str(),
381  ftplib::transfermode::image))
382  {
383  errorMsg = "*** ERROR: ftp.Get failed. ***\n";
384  success = false;
385  }
386  }
387  }
388  }
389  }
390  else
391  {
392  errorMsg = "*** ERROR: ftp.Chdir failed. ***\n";
393  success = false;
394  }
395  }
396  else
397  {
398  errorMsg = "*** ERROR: ftp.Login failed. ***\n";
399  success = false;
400  }
401  }
402  else
403  {
404  errorMsg = "*** ERROR: ftp.Connect failed. ***\n";
405  success = false;
406  }
407 
408  ftp.Quit();
409  return success;
410 }
411 //-----------------------------------------------------------------------------
412 //! Get a list of all filenames with given search file tag in remote directory
413 /*!
414  *
415  * \param ftp
416  * \param localDir
417  * \param searchFileTag
418  * \param retrievedFileNames
419  * \param errorMsg
420  * \return
421  */
422 bool getAllFileNamesWithTag(ftplib& ftp,
423  const string& localDir,
424  const string& searchFileTag,
425  vector<string>& retrievedFileNames,
426  string& errorMsg)
427 {
428  bool success = true;
429  string ftpDirResult = localDir + "ftpDirResult.txt";
430  string searchDirAndFileType = "*." + searchFileTag;
431 
432  // Get result of ftp.Dir into the text file ftpDirResult
433  if (ftp.Dir(ftpDirResult.c_str(), searchDirAndFileType.c_str()))
434  {
435  // analyse ftpDirResult content
436  vector<string> vecFilesInDir;
437  vector<string> strippedFiles;
438 
439  if (Utils::getFileContent(ftpDirResult, vecFilesInDir))
440  {
441  for (string& fileInfoLine : vecFilesInDir)
442  {
443  vector<string> splits;
444  Utils::splitString(fileInfoLine, ' ', splits);
445  // we have to remove the first 8 strings with first 8 "holes" of unknown length from info line
446  int numOfFoundNonEmpty = 0;
447  bool found = false;
448 
449  int pos = 0;
450  while (pos < splits.size())
451  {
452  if (!splits[pos].empty())
453  numOfFoundNonEmpty++;
454 
455  if (numOfFoundNonEmpty == 8)
456  {
457  found = true;
458  break;
459  }
460  pos++;
461  }
462  // remove next string that we assume to be empty (before interesting part)
463  pos++;
464 
465  // we need minumum 9 splits (compare content of ftpDirResult.txt). The splits after the 8th we combine to one string again
466  if (found && pos < splits.size())
467  {
468  std::string name;
469  std::string space(" ");
470  for (int i = pos; i < splits.size(); ++i)
471  {
472  name.append(splits[i]);
473  if (i != splits.size() - 1)
474  name.append(space);
475  }
476 
477  if (name.size())
478  retrievedFileNames.push_back(name);
479  }
480  else
481  {
482  // if more than two splits double point is not unique and we get an undefined result
483  errorMsg = "*** ERROR: getAllFileNamesWithTag: Unexpected result: Ftp info line was not formatted as expected. ***\n";
484  success = false;
485  }
486  }
487  }
488  }
489  else
490  {
491  if (!Utils::dirExists(localDir))
492  {
493  errorMsg = "*** ERROR: getAllFileNamesWithTag: directory " + localDir + "does not exist. ***\n";
494  }
495  else
496  {
497  errorMsg = "*** ERROR: getAllFileNamesWithTag failed. ***\n";
498  }
499  success = false;
500  }
501 
502  return success;
503 }
504 //-----------------------------------------------------------------------------
505 //! Returns the latest fileName of the same fullPathAndFilename
506 /*!
507  *
508  * \param ftp
509  * \param fileDir
510  * \param fileName
511  * \return
512  */
513 string getLatestFilename(ftplib& ftp,
514  const string& fileDir,
515  const string& fileName)
516 {
517  // Get a list of files
518  string fullPathAndFilename = fileDir + fileName;
519  string ftpDirResult = fileDir + "ftpDirResult.txt";
520  string filenameWOExt = Utils::getFileNameWOExt(fullPathAndFilename);
521  string filenameWOExtStar = filenameWOExt + "*";
522 
523  // Get result of ftp.Dir into the textfile ftpDirResult
524  if (ftp.Dir(ftpDirResult.c_str(), filenameWOExtStar.c_str()))
525  {
526  vector<string> vecFilesInDir;
527  vector<string> strippedFiles;
528 
529  if (Utils::getFileContent(ftpDirResult, vecFilesInDir))
530  {
531  for (string& fileInfoLine : vecFilesInDir)
532  {
533  size_t foundAt = fileInfoLine.find(filenameWOExt);
534  if (foundAt != string::npos)
535  {
536  string fileWExt = fileInfoLine.substr(foundAt);
537  string fileWOExt = Utils::getFileNameWOExt(fileWExt);
538  strippedFiles.push_back(fileWOExt);
539  }
540  }
541  }
542 
543  if (!strippedFiles.empty())
544  {
545  // sort fileName naturally as many file systems do.
546  sort(strippedFiles.begin(), strippedFiles.end(), Utils::compareNatural);
547  string latest = strippedFiles.back() + ".xml";
548  return latest;
549  }
550  else
551  return "";
552  }
553 
554  // Return empty for not found
555  return "";
556 }
557 //-----------------------------------------------------------------------------
558 //! Returns the version number at the end of the fileName
559 /*!
560  *
561  * \param filename Filename on ftp server with an ending *(#).ext
562  * \return Returns the number in the brackets at the end of the filename
563  */
564 int getVersionInFilename(const string& filename)
565 {
566  string filenameWOExt = Utils::getFileNameWOExt(filename);
567 
568  int versionNO = 0;
569  if (!filenameWOExt.empty())
570  {
571  size_t len = filenameWOExt.length();
572  if (filenameWOExt.at(len - 1) == ')')
573  {
574  size_t leftPos = filenameWOExt.rfind('(');
575  string verStr = filenameWOExt.substr(leftPos + 1, len - leftPos - 2);
576  versionNO = stoi(verStr);
577  }
578  }
579  return versionNO;
580 }
581 //-----------------------------------------------------------------------------
582 // off64_t ftpUploadSizeMax = 0;
583 
584 //-----------------------------------------------------------------------------
585 //! Calibration Upload callback for progress feedback
586 // int ftpCallbackUpload(off64_t xfered, void* arg)
587 //{
588 // if (ftpUploadSizeMax)
589 // {
590 // int xferedPC = (int)((float)xfered / (float)ftpUploadSizeMax * 100.0f);
591 // cout << "Bytes saved: " << xfered << " (" << xferedPC << ")" << endl;
592 // }
593 // else
594 // {
595 // cout << "Bytes saved: " << xfered << endl;
596 // }
597 // return xfered ? 1 : 0;
598 // }
599 };
600 
601 #endif
FtpUtils provides networking functionality via the FTP protocol.
Definition: FtpUtils.cpp:21
bool getAllFileNamesWithTag(ftplib &ftp, const string &localDir, const string &searchFileTag, vector< string > &retrievedFileNames, string &errorMsg)
Get a list of all filenames with given search file tag in remote directory.
Definition: FtpUtils.cpp:422
string getLatestFilename(ftplib &ftp, const string &fileDir, const string &fileName)
Returns the latest fileName of the same fullPathAndFilename.
Definition: FtpUtils.cpp:513
bool uploadFile(const string &fileDir, const string &fileName, const string &ftpHost, const string &ftpUser, const string &ftpPwd, const string &ftpDir, string &errorMsg)
Uploads file to the ftp server.
Definition: FtpUtils.cpp:198
bool downloadAllFilesFromDir(const string &fileDir, const string &ftpHost, const string &ftpUser, const string &ftpPwd, const string &ftpDir, const string &searchFileTag, string &errorMsg)
Definition: FtpUtils.cpp:342
bool downloadFile(const string &fileDir, const string &fileName, const string &ftpHost, const string &ftpUser, const string &ftpPwd, const string &ftpDir, string &errorMsg)
Download file from the ftp server.
Definition: FtpUtils.cpp:267
int getVersionInFilename(const string &filename)
Returns the version number at the end of the fileName.
Definition: FtpUtils.cpp:564
bool uploadFileLatestVersion(const string &fileDir, const string &fileName, const string &ftpHost, const string &ftpUser, const string &ftpPwd, const string &ftpDir, string &errorMsg)
Uploads the file to the ftp server. Checks if the filename already exists and adds a version number.
Definition: FtpUtils.cpp:34
bool downloadFileLatestVersion(const string &fileDir, const string &fileName, const string &ftpHost, const string &ftpUser, const string &ftpPwd, const string &ftpDir, string &errorMsg)
Download the file from the ftp server which has the latest version and store it as fileName locally.
Definition: FtpUtils.cpp:121
bool fileExists(const string &pathfilename)
Returns true if a file exists.
Definition: Utils.cpp:897
bool dirExists(const string &path)
Returns true if a directory exists.
Definition: Utils.cpp:790
bool getFileContent(const string &fileName, vector< string > &vecOfStrings)
Returns true if content of file could be put in a vector of strings.
Definition: Utils.cpp:411
void errorMsg(const char *tag, const char *msg, const int line, const char *file)
Platform independent error message output.
Definition: Utils.cpp:1168
string getFileNameWOExt(const string &pathFilename)
Returns the filename without extension.
Definition: Utils.cpp:616
bool compareNatural(const string &a, const string &b)
Naturally compares two strings (used for filename sorting)
Definition: Utils.cpp:464
void splitString(const string &s, char delimiter, vector< string > &splits)
Splits an input string at a delimiter character into a string vector.
Definition: Utils.cpp:152