1 // ==============================================================
2 //	This file is part of MegaGlest Shared Library (www.glest.org)
3 //
4 //	Copyright (C) 2009-2010 Titus Tscharntke (info@titusgames.de) and
5 //                          Mark Vejvoda (mark_vejvoda@hotmail.com)
6 //
7 //	You can redistribute this code and/or modify it under
8 //	the terms of the GNU General Public License as published
9 //	by the Free Software Foundation; either version 2 of the
10 //	License, or (at your option) any later version
11 // ==============================================================
12 
13 #include "miniftpclient.h"
14 #include "util.h"
15 #include "platform_common.h"
16 
17 #include <curl/curl.h>
18 #include <curl/easy.h>
19 #include <algorithm>
20 #include "conversion.h"
21 #include "platform_util.h"
22 
23 using namespace Shared::Util;
24 using namespace Shared::PlatformCommon;
25 
26 namespace Shared { namespace PlatformCommon {
27 
28 static const char *FTP_MAPS_CUSTOM_USERNAME        = "maps_custom";
29 static const char *FTP_MAPS_USERNAME               = "maps";
30 static const char *FTP_TILESETS_CUSTOM_USERNAME    = "tilesets_custom";
31 static const char *FTP_TILESETS_USERNAME           = "tilesets";
32 static const char *FTP_TECHTREES_CUSTOM_USERNAME   = "techtrees_custom";
33 static const char *FTP_TECHTREES_USERNAME          = "techtrees";
34 
35 static const char *FTP_TEMPFILES_USERNAME          = "temp";
36 
37 static const char *FTP_COMMON_PASSWORD             = "mg_ftp_server";
38 
39 /*
40  * This is an example showing how to get a single file from an FTP server.
41  * It delays the actual destination file creation until the first write
42  * callback so that it won't create an empty file in case the remote file
43  * doesn't exist or something else fails.
44  */
45 
46 struct FtpFile {
47   const char *itemName;
48   const char *filename;
49   const char *filepath;
50   FILE *stream;
51   FTPClientThread *ftpServer;
52   string currentFilename;
53   bool isValidXfer;
54   FTP_Client_CallbackType downloadType;
55 };
56 
my_fwrite(void * buffer,size_t size,size_t nmemb,void * stream)57 static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) {
58     struct FtpFile *out=(struct FtpFile *)stream;
59 
60     string fullFilePath = "";
61     if(out != NULL && out->filepath != NULL) {
62         fullFilePath = out->filepath;
63     }
64     if(out != NULL && out->filename != NULL) {
65         fullFilePath += out->filename;
66     }
67 
68     if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread writing to file [%s]\n",fullFilePath.c_str());
69     //printf ("===> FTP Client thread writing to file [%s]\n",fullFilePath.c_str());
70 
71     // Abort file xfer and delete partial file
72     if(out && out->ftpServer && out->ftpServer->getQuitStatus() == true) {
73         if(out->stream) {
74             fclose(out->stream);
75             out->stream = NULL;
76         }
77 
78         if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread CANCELLED, deleting file for writing [%s]\n",fullFilePath.c_str());
79         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread CANCELLED, deleting file for writing [%s]\n",fullFilePath.c_str());
80 
81 
82         removeFile(fullFilePath);
83         return 0;
84     }
85 
86     if(out && out->stream == NULL) {
87         if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread opening file for writing [%s]\n",fullFilePath.c_str());
88         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread opening file for writing [%s]\n",fullFilePath.c_str());
89 
90         /* open file for writing */
91 #ifdef WIN32
92 		out->stream= _wfopen(utf8_decode(fullFilePath).c_str(), L"wb");
93 #else
94         out->stream = fopen(fullFilePath.c_str(), "wb");
95 #endif
96         if(out->stream == NULL) {
97           if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
98           if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
99           SystemFlags::OutputDebug(SystemFlags::debugError,"===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
100           return 0; /* failure, can't open file to write */
101         }
102 
103         out->isValidXfer = true;
104     }
105     else if(out == NULL) {
106         if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> #2 FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
107         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> #2 FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
108         SystemFlags::OutputDebug(SystemFlags::debugError,"===> #2 FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
109         return 0; /* failure, can't open file to write */
110     }
111 
112     size_t result = fwrite(buffer, size, nmemb, out->stream);
113     if(result != nmemb) {
114         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread FAILED to write data chunk to file [%s] nmemb = " MG_SIZE_T_SPECIFIER ", result = " MG_SIZE_T_SPECIFIER "\n",fullFilePath.c_str(),nmemb,result);
115         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread FAILED to write data chunk to file [%s] nmemb = " MG_SIZE_T_SPECIFIER ", result = " MG_SIZE_T_SPECIFIER "\n",fullFilePath.c_str(),nmemb,result);
116         SystemFlags::OutputDebug(SystemFlags::debugError,"===> FTP Client thread FAILED to write data chunk to file [%s] nmemb = " MG_SIZE_T_SPECIFIER ", result = " MG_SIZE_T_SPECIFIER "\n",fullFilePath.c_str(),nmemb,result);
117         //return -1; /* failure, can't open file to write */
118     }
119     return result;
120 }
121 
122 /*
123 static long file_is_comming(struct curl_fileinfo *finfo,void *data,int remains) {
124     struct FtpFile *out=(struct FtpFile *)data;
125 
126     string rootFilePath = "";
127     string fullFilePath = "";
128     if(out != NULL && out->filepath != NULL) {
129         rootFilePath = out->filepath;
130     }
131     if(out != NULL && out->filename != NULL) {
132         fullFilePath = rootFilePath + finfo->filename;
133     }
134 
135     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n===> FTP Client thread file_is_comming: remains: [%3d] filename: [%s] size: [%10luB] ", remains, finfo->filename,(unsigned long)finfo->size);
136     SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread file_is_comming: remains: [%3d] filename: [%s] size: [%10luB] ", remains, finfo->filename,(unsigned long)finfo->size);
137 
138     if(out != NULL) {
139         //out->currentFilename = finfo->filename;
140         out->currentFilename = fullFilePath;
141 
142         if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" current filename: [%s] ", fullFilePath.c_str());
143         SystemFlags::OutputDebug(SystemFlags::debugNetwork,"current filename: [%s] ", fullFilePath.c_str());
144     }
145 
146     switch(finfo->filetype) {
147         case CURLFILETYPE_DIRECTORY:
148             if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" DIR (creating [%s%s])\n",rootFilePath.c_str(),finfo->filename);
149             SystemFlags::OutputDebug(SystemFlags::debugNetwork," DIR (creating [%s%s])\n",rootFilePath.c_str(),finfo->filename);
150 
151             rootFilePath += finfo->filename;
152             createDirectoryPaths(rootFilePath.c_str());
153             break;
154         case CURLFILETYPE_FILE:
155             if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" FILE ");
156             SystemFlags::OutputDebug(SystemFlags::debugNetwork," FILE ");
157             break;
158         default:
159             if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" OTHER\n");
160             SystemFlags::OutputDebug(SystemFlags::debugNetwork," OTHER\n");
161             break;
162     }
163 
164     if(finfo->filetype == CURLFILETYPE_FILE) {
165         // do not transfer files >= 50B
166         //if(finfo->size > 50) {
167         //  printf("SKIPPED\n");
168         //  return CURL_CHUNK_BGN_FUNC_SKIP;
169         //}
170 
171         if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" opening file [%s] ", fullFilePath.c_str());
172         SystemFlags::OutputDebug(SystemFlags::debugNetwork," opening file [%s] ", fullFilePath.c_str());
173 
174         out->stream = fopen(fullFilePath.c_str(), "wb");
175         if(out->stream == NULL) {
176             if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
177             SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str());
178 
179             return CURL_CHUNK_BGN_FUNC_FAIL;
180         }
181     }
182 
183     out->isValidXfer = true;
184     return CURL_CHUNK_BGN_FUNC_OK;
185 }
186 
187 static long file_is_downloaded(void *data) {
188     struct FtpFile *out=(struct FtpFile *)data;
189     if(out->stream) {
190         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("DOWNLOAD COMPLETE!\n");
191         SystemFlags::OutputDebug(SystemFlags::debugNetwork,"DOWNLOAD COMPLETE!\n");
192 
193         fclose(out->stream);
194         out->stream = NULL;
195     }
196     return CURL_CHUNK_END_FUNC_OK;
197 }
198 */
199 
file_progress(struct FtpFile * out,double download_total,double download_now,double upload_total,double upload_now)200 int file_progress(struct FtpFile *out,double download_total, double download_now, double upload_total,double upload_now) {
201   //if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" download progress [%f][%f][%f][%f] ",download_total,download_now,upload_total,upload_now);
202 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork," download progress [%f][%f][%f][%f] ",download_total,download_now,upload_total,upload_now);
203 
204   if(out != NULL &&
205      out->ftpServer != NULL &&
206      out->ftpServer->getCallBackObject() != NULL) {
207          if(out->ftpServer->getQuitStatus() == true) {
208              if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread CANCELLED\n");
209              if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread CANCELLED\n");
210 
211              return -1;
212          }
213          FTPClientCallbackInterface::FtpProgressStats stats;
214          stats.download_total   = download_total;
215          stats.download_now     = download_now;
216          stats.upload_total     = upload_total;
217          stats.upload_now       = upload_now;
218          stats.currentFilename  = out->currentFilename;
219          stats.downloadType		= out->downloadType;
220 
221          static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
222          MutexSafeWrapper safeMutex(out->ftpServer->getProgressMutex(),mutexOwnerId);
223          out->ftpServer->getProgressMutex()->setOwnerId(mutexOwnerId);
224          out->ftpServer->getCallBackObject()->FTPClient_CallbackEvent(
225         		 out->itemName,
226         		 ftp_cct_DownloadProgress,
227         		 make_pair(ftp_crt_SUCCESS,""),
228         		 &stats);
229   }
230 
231   return 0;
232 }
233 
FTPClientThread(int portNumber,string serverUrl,std::pair<string,string> mapsPath,std::pair<string,string> tilesetsPath,std::pair<string,string> techtreesPath,std::pair<string,string> scenariosPath,FTPClientCallbackInterface * pCBObject,string fileArchiveExtension,string fileArchiveExtractCommand,string fileArchiveExtractCommandParameters,int fileArchiveExtractCommandSuccessResult,string tempFilesPath)234 FTPClientThread::FTPClientThread(int portNumber, string serverUrl,
235 		std::pair<string,string> mapsPath,
236 		std::pair<string,string> tilesetsPath,
237 		std::pair<string,string> techtreesPath,
238 		std::pair<string,string> scenariosPath,
239 		FTPClientCallbackInterface *pCBObject,
240 		string fileArchiveExtension,
241 		string fileArchiveExtractCommand,
242 		string fileArchiveExtractCommandParameters,
243 		int fileArchiveExtractCommandSuccessResult,
244 		string tempFilesPath) : BaseThread() {
245 
246 	uniqueID = "FTPClientThread";
247     this->portNumber    = portNumber;
248     this->serverUrl     = serverUrl;
249     this->mapsPath      = mapsPath;
250     this->tilesetsPath  = tilesetsPath;
251     this->techtreesPath = techtreesPath;
252     this->scenariosPath	= scenariosPath;
253     this->pCBObject     = pCBObject;
254     this->shellCommandCallbackUserData = "";
255 
256     this->fileArchiveExtension = fileArchiveExtension;
257     this->fileArchiveExtractCommand = fileArchiveExtractCommand;
258     this->fileArchiveExtractCommandParameters = fileArchiveExtractCommandParameters;
259     this->fileArchiveExtractCommandSuccessResult = fileArchiveExtractCommandSuccessResult;
260     this->tempFilesPath = tempFilesPath;
261 
262     if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] Using FTP port #: %d, serverUrl [%s]\n",__FILE__,__FUNCTION__,__LINE__,portNumber,serverUrl.c_str());
263 }
264 
signalQuit()265 void FTPClientThread::signalQuit() {
266     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client: signalQuit\n");
267     if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client: signalQuit\n");
268     BaseThread::signalQuit();
269 }
270 
shutdownAndWait()271 bool FTPClientThread::shutdownAndWait() {
272     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client: shutdownAndWait\n");
273     if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client: shutdownAndWait\n");
274 
275     signalQuit();
276     return BaseThread::shutdownAndWait();
277 }
278 
279 
getMapFromServer(pair<string,string> mapFileName,string ftpUser,string ftpUserPassword)280 pair<FTP_Client_ResultType,string> FTPClientThread::getMapFromServer(pair<string,string> mapFileName, string ftpUser, string ftpUserPassword) {
281 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
282 
283     string destFileExt = "";
284     string destFile = this->mapsPath.second;
285 
286 	endPathWithSlash(destFile);
287     destFile += mapFileName.first;
288 
289     if(mapFileName.second == "") {
290 		if(EndsWith(destFile,".mgm") == false && EndsWith(destFile,".gbm") == false) {
291 			destFileExt = ".mgm";
292 			destFile += destFileExt;
293 		}
294     }
295 
296     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread about to try to RETR into [%s]\n",destFile.c_str());
297     if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread about to try to RETR into [%s]\n",destFile.c_str());
298 
299     struct FtpFile ftpfile = {
300         NULL,
301         destFile.c_str(), /* name to store the file as if succesful */
302         NULL,
303         NULL,
304         this,
305         "",
306         false,
307         ftp_cct_Map
308     };
309 
310     CURL *curl = SystemFlags::initHTTP();
311     if(curl) {
312         ftpfile.stream = NULL;
313 
314         char szBuf[8096]="";
315         if(mapFileName.second != "") {
316         	snprintf(szBuf,8096,"%s",mapFileName.second.c_str());
317         	curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
318         }
319         else {
320         	snprintf(szBuf,8096,"ftp://%s:%s@%s:%d/%s%s",ftpUser.c_str(),ftpUserPassword.c_str(),serverUrl.c_str(),portNumber,mapFileName.first.c_str(),destFileExt.c_str());
321         }
322 
323         curl_easy_setopt(curl, CURLOPT_URL,szBuf);
324         curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
325 
326         /* Define our callback to get called when there's data to be written */
327         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
328         /* Set a pointer to our struct to pass to the callback */
329         curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
330 
331 
332         // Max 10 minutes to transfer
333         //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 600);
334         // Max 60 minutes to transfer
335         curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3600L);
336         curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, 120L);
337 
338         /* Switch on full protocol/debug output */
339         if(SystemFlags::VERBOSE_MODE_ENABLED) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
340 
341         CURLcode res = curl_easy_perform(curl);
342         if(res != CURLE_OK) {
343           result.second = curl_easy_strerror(res);
344           // we failed
345           printf("curl FAILED with: %d [%s] szBuf [%s]\n", res,curl_easy_strerror(res),szBuf);
346           if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"curl FAILED with: %d [%s] szBuf [%s]\n", res,curl_easy_strerror(res),szBuf);
347 
348           if(res == CURLE_PARTIAL_FILE) {
349         	  result.first = ftp_crt_PARTIALFAIL;
350           }
351           else if(res == CURLE_COULDNT_CONNECT) {
352         	  result.first = ftp_crt_HOST_NOT_ACCEPTING;
353           }
354         }
355         else {
356             result.first = ftp_crt_SUCCESS;
357         }
358 
359         SystemFlags::cleanupHTTP(&curl);
360     }
361 
362     if(ftpfile.stream) {
363         fclose(ftpfile.stream);
364         ftpfile.stream = NULL;
365     }
366     if(result.first != ftp_crt_SUCCESS) {
367     	removeFile(destFile);
368     }
369 
370     return result;
371 }
372 
getMapFromServer(pair<string,string> mapFileName)373 void FTPClientThread::getMapFromServer(pair<string,string> mapFileName) {
374 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
375 	if(mapFileName.second != "") {
376 		result = getMapFromServer(mapFileName, "", "");
377 	}
378 	else {
379 		pair<string,string> findMapFileName = mapFileName;
380 		findMapFileName.first += + ".mgm";
381 
382 		result = getMapFromServer(findMapFileName, FTP_MAPS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD);
383 		if(result.first == ftp_crt_FAIL && this->getQuitStatus() == false) {
384 			findMapFileName = mapFileName;
385 			findMapFileName.first += + ".gbm";
386 			result = getMapFromServer(findMapFileName, FTP_MAPS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD);
387 			if(result.first == ftp_crt_FAIL && this->getQuitStatus() == false) {
388 				findMapFileName = mapFileName;
389 				findMapFileName.first += + ".mgm";
390 				result = getMapFromServer(findMapFileName, FTP_MAPS_USERNAME, FTP_COMMON_PASSWORD);
391 				if(result.first == ftp_crt_FAIL && this->getQuitStatus() == false) {
392 					findMapFileName = mapFileName;
393 					findMapFileName.first += + ".gbm";
394 					result = getMapFromServer(findMapFileName, FTP_MAPS_USERNAME, FTP_COMMON_PASSWORD);
395 				}
396 			}
397 		}
398 	}
399 
400 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
401     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
402     this->getProgressMutex()->setOwnerId(mutexOwnerId);
403     if(this->pCBObject != NULL) {
404         this->pCBObject->FTPClient_CallbackEvent(
405         		mapFileName.first,
406         		ftp_cct_Map,
407         		result,
408         		NULL);
409     }
410 }
411 
addMapToRequests(string mapFilename,string URL)412 void FTPClientThread::addMapToRequests(string mapFilename,string URL) {
413 	std::pair<string,string> item = make_pair(mapFilename,URL);
414 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
415     MutexSafeWrapper safeMutex(&mutexMapFileList,mutexOwnerId);
416     mutexMapFileList.setOwnerId(mutexOwnerId);
417     if(std::find(mapFileList.begin(),mapFileList.end(),item) == mapFileList.end()) {
418         mapFileList.push_back(item);
419     }
420 }
421 
addTilesetToRequests(string tileSetName,string URL)422 void FTPClientThread::addTilesetToRequests(string tileSetName,string URL) {
423 	std::pair<string,string> item = make_pair(tileSetName,URL);
424 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
425     MutexSafeWrapper safeMutex(&mutexTilesetList,mutexOwnerId);
426     mutexTilesetList.setOwnerId(mutexOwnerId);
427     if(std::find(tilesetList.begin(),tilesetList.end(),item) == tilesetList.end()) {
428         tilesetList.push_back(item);
429     }
430 }
431 
addTechtreeToRequests(string techtreeName,string URL)432 void FTPClientThread::addTechtreeToRequests(string techtreeName,string URL) {
433 	std::pair<string,string> item = make_pair(techtreeName,URL);
434 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
435     MutexSafeWrapper safeMutex(&mutexTechtreeList,mutexOwnerId);
436     mutexTechtreeList.setOwnerId(mutexOwnerId);
437     if(std::find(techtreeList.begin(),techtreeList.end(),item) == techtreeList.end()) {
438     	techtreeList.push_back(item);
439     }
440 }
441 
addScenarioToRequests(string fileName,string URL)442 void FTPClientThread::addScenarioToRequests(string fileName,string URL) {
443 	std::pair<string,string> item = make_pair(fileName,URL);
444 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
445     MutexSafeWrapper safeMutex(&mutexScenarioList,mutexOwnerId);
446     mutexScenarioList.setOwnerId(mutexOwnerId);
447     if(std::find(scenarioList.begin(),scenarioList.end(),item) == scenarioList.end()) {
448     	scenarioList.push_back(item);
449     }
450 }
451 
addFileToRequests(string fileName,string URL)452 void FTPClientThread::addFileToRequests(string fileName,string URL) {
453 	std::pair<string,string> item = make_pair(fileName,URL);
454 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
455     MutexSafeWrapper safeMutex(&mutexFileList,mutexOwnerId);
456     mutexFileList.setOwnerId(mutexOwnerId);
457     if(std::find(fileList.begin(),fileList.end(),item) == fileList.end()) {
458     	fileList.push_back(item);
459     }
460 }
461 
addTempFileToRequests(string fileName,string URL)462 void FTPClientThread::addTempFileToRequests(string fileName,string URL) {
463 	std::pair<string,string> item = make_pair(fileName,URL);
464 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
465     MutexSafeWrapper safeMutex(&mutexTempFileList,mutexOwnerId);
466     mutexTempFileList.setOwnerId(mutexOwnerId);
467     if(std::find(tempFileList.begin(),tempFileList.end(),item) == tempFileList.end()) {
468     	tempFileList.push_back(item);
469     }
470 }
471 
getTilesetFromServer(pair<string,string> tileSetName)472 void FTPClientThread::getTilesetFromServer(pair<string,string> tileSetName) {
473 	bool findArchive = executeShellCommand(
474 			this->fileArchiveExtractCommand,
475 			this->fileArchiveExtractCommandSuccessResult);
476 
477 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
478 	if(findArchive == true) {
479 		if(tileSetName.second != "") {
480 			//result = getTilesetFromServer(tileSetName, "", "", "", findArchive);
481 			result = getTilesetFromServer(tileSetName, "", "", "", true);
482 		}
483 		else {
484 			//result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, findArchive);
485 			result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, true);
486 			if(result.first == ftp_crt_FAIL && this->getQuitStatus() == false) {
487 				//if(findArchive == true) {
488 					//result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, false);
489 				result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, true);
490 				//}
491 				if(result.first == ftp_crt_FAIL && this->getQuitStatus() == false) {
492 				//	result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_USERNAME, FTP_COMMON_PASSWORD, findArchive);
493 					result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_USERNAME, FTP_COMMON_PASSWORD, true);
494 
495 				//	if(findArchive == true) {
496 				//		result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_USERNAME, FTP_COMMON_PASSWORD, false);
497 				//	}
498 				}
499 			}
500 		}
501 	}
502 
503 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
504     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
505     this->getProgressMutex()->setOwnerId(mutexOwnerId);
506     if(this->pCBObject != NULL) {
507         this->pCBObject->FTPClient_CallbackEvent(
508         		tileSetName.first,
509         		ftp_cct_Tileset,
510         		result,
511         		NULL);
512     }
513 }
514 
getTilesetFromServer(pair<string,string> tileSetName,string tileSetNameSubfolder,string ftpUser,string ftpUserPassword,bool findArchive)515 pair<FTP_Client_ResultType,string> FTPClientThread::getTilesetFromServer(
516 												pair<string,string> tileSetName,
517 												string tileSetNameSubfolder,
518 												string ftpUser,
519 												string ftpUserPassword,
520 												bool findArchive) {
521 
522 	string destFileSaveAsNewFile = "";
523 	string destFileSaveAs = "";
524 	string remotePath = "";
525 	bool getFolderContents = false;
526 	vector<string> wantDirListOnly;
527 
528     if(tileSetNameSubfolder == "") {
529         if(findArchive == true) {
530         	destFileSaveAs = this->tilesetsPath.second;
531             endPathWithSlash(destFileSaveAs);
532             destFileSaveAs += tileSetName.first + this->fileArchiveExtension;
533 
534             if(tileSetName.second != "") {
535             	remotePath = tileSetName.second;
536             }
537             else {
538             	remotePath = tileSetName.first + this->fileArchiveExtension;
539             }
540         }
541         else {
542         	getFolderContents = true;
543         	remotePath = tileSetName.first + "/";
544         	destFileSaveAs = this->tilesetsPath.second;
545             endPathWithSlash(destFileSaveAs);
546             destFileSaveAs += tileSetName.first;
547             destFileSaveAsNewFile = destFileSaveAs;
548             endPathWithSlash(destFileSaveAsNewFile);
549             destFileSaveAs += ".tmp";
550         }
551     }
552     else {
553     	getFolderContents = true;
554     	remotePath = tileSetName.first + "/" + tileSetNameSubfolder + "/";
555     	destFileSaveAs = this->tilesetsPath.second;
556         endPathWithSlash(destFileSaveAs);
557         destFileSaveAs += tileSetName.first;
558         endPathWithSlash(destFileSaveAs);
559 
560         destFileSaveAs += tileSetNameSubfolder;
561         destFileSaveAsNewFile = destFileSaveAs;
562         endPathWithSlash(destFileSaveAsNewFile);
563         destFileSaveAs += ".tmp";
564     }
565 
566     vector <string> *pWantDirListOnly = NULL;
567     if(getFolderContents == true) {
568     	pWantDirListOnly = &wantDirListOnly;
569     }
570 
571     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("FTPClientThread::getTilesetFromServer [%s] remotePath [%s] destFileSaveAs [%s] getFolderContents = %d findArchive = %d\n",tileSetName.first.c_str(),remotePath.c_str(),destFileSaveAs.c_str(),getFolderContents,findArchive);
572 
573     pair<FTP_Client_ResultType,string> result = getFileFromServer(
574     		ftp_cct_Tileset,
575     		tileSetName,
576     		remotePath,
577     		destFileSaveAs,
578     		ftpUser,
579     		ftpUserPassword,
580     		pWantDirListOnly);
581 
582     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("FTPClientThread::getTilesetFromServer [%s] remotePath [%s] destFileSaveAs [%s] getFolderContents = %d result.first = %d [%s] findArchive = %d\n",tileSetName.first.c_str(),remotePath.c_str(),destFileSaveAs.c_str(),getFolderContents,result.first,result.second.c_str(),findArchive);
583 
584     // Extract the archive
585     if(result.first == ftp_crt_SUCCESS) {
586     	if(findArchive == true) {
587     	    string destRootArchiveFolder = this->tilesetsPath.second;
588    	        endPathWithSlash(destRootArchiveFolder);
589 
590 			string extractCmd = getFullFileArchiveExtractCommand(
591 					this->fileArchiveExtractCommand,
592 					this->fileArchiveExtractCommandParameters,
593 					destRootArchiveFolder,
594 					destRootArchiveFolder + tileSetName.first + this->fileArchiveExtension);
595 
596 			static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
597 		    MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
598 		    this->getProgressMutex()->setOwnerId(mutexOwnerId);
599 
600 		    if(this->pCBObject != NULL) {
601 		    	this->shellCommandCallbackUserData = tileSetName.first;
602 		        this->pCBObject->FTPClient_CallbackEvent(
603 		        		tileSetName.first,
604 		        		ftp_cct_ExtractProgress,
605 		        		make_pair(ftp_crt_SUCCESS,"extracting"),NULL);
606 		    }
607 		    safeMutex.ReleaseLock();
608 
609 			if(executeShellCommand(extractCmd,this->fileArchiveExtractCommandSuccessResult,this) == false) {
610 				result.first = ftp_crt_FAIL;
611 				result.second = "failed to extract archive!";
612 			}
613 
614 			return result;
615     	}
616     	else {
617     		if(getFolderContents == true) {
618     			removeFile(destFileSaveAs);
619 
620     			for(unsigned int i = 0; i < wantDirListOnly.size(); ++i) {
621     				string fileFromList = wantDirListOnly[i];
622 
623     				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("fileFromList [%s] i [%u]\n",fileFromList.c_str(),i);
624 
625     				if( fileFromList != "models" && fileFromList != "textures" &&
626     					fileFromList != "sounds") {
627 						result = getFileFromServer(ftp_cct_Tileset,
628 								tileSetName,
629 								remotePath + fileFromList,
630 								destFileSaveAsNewFile + fileFromList,
631 								ftpUser, ftpUserPassword);
632 						if(result.first != ftp_crt_SUCCESS) {
633 							break;
634 						}
635     				}
636     				else {
637     					result = getTilesetFromServer(tileSetName,
638     							fileFromList, ftpUser, ftpUserPassword,
639     							findArchive);
640 						if(result.first != ftp_crt_SUCCESS) {
641 							break;
642 						}
643     				}
644     			}
645     		}
646     	}
647     }
648 
649     if(result.first != ftp_crt_SUCCESS && findArchive == false) {
650         string destRootFolder = this->tilesetsPath.second;
651         endPathWithSlash(destRootFolder);
652         destRootFolder += tileSetName.first;
653         endPathWithSlash(destRootFolder);
654 
655         removeFolder(destRootFolder);
656     }
657 
658     return result;
659 }
660 
getTechtreeFromServer(pair<string,string> techtreeName)661 void FTPClientThread::getTechtreeFromServer(pair<string,string> techtreeName) {
662 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
663 	bool findArchive = executeShellCommand(
664 			this->fileArchiveExtractCommand,
665 			this->fileArchiveExtractCommandSuccessResult);
666 	if(findArchive == true) {
667 		if(techtreeName.second != "") {
668 			result = getTechtreeFromServer(techtreeName, "", "");
669 		}
670 		else {
671 			result = getTechtreeFromServer(techtreeName, FTP_TECHTREES_CUSTOM_USERNAME, FTP_COMMON_PASSWORD);
672 			if(result.first == ftp_crt_FAIL && this->getQuitStatus() == false) {
673 				result = getTechtreeFromServer(techtreeName, FTP_TECHTREES_USERNAME, FTP_COMMON_PASSWORD);
674 			}
675 		}
676 	}
677 
678 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
679     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
680     this->getProgressMutex()->setOwnerId(mutexOwnerId);
681     if(this->pCBObject != NULL) {
682         this->pCBObject->FTPClient_CallbackEvent(
683         		techtreeName.first,
684         		ftp_cct_Techtree,
685         		result,
686         		NULL);
687     }
688 }
689 
getTechtreeFromServer(pair<string,string> techtreeName,string ftpUser,string ftpUserPassword)690 pair<FTP_Client_ResultType,string>  FTPClientThread::getTechtreeFromServer(pair<string,string> techtreeName,
691 		string ftpUser, string ftpUserPassword) {
692 
693     // Root folder for the techtree
694     string destRootFolder = this->techtreesPath.second;
695 	endPathWithSlash(destRootFolder);
696 	string destRootArchiveFolder = destRootFolder;
697 	destRootFolder += techtreeName.first;
698 	endPathWithSlash(destRootFolder);
699 
700 	string destFile = this->techtreesPath.second;
701 	endPathWithSlash(destFile);
702     destFile += techtreeName.first;
703     string destFileSaveAs = destFile + this->fileArchiveExtension;
704     endPathWithSlash(destFile);
705 
706     string remotePath = techtreeName.first + this->fileArchiveExtension;
707     if(techtreeName.second != "") {
708     	remotePath = techtreeName.second;
709     }
710 
711     pair<FTP_Client_ResultType,string> result = getFileFromServer(ftp_cct_Techtree,
712     		techtreeName, remotePath, destFileSaveAs, ftpUser, ftpUserPassword);
713 
714     // Extract the archive
715     if(result.first == ftp_crt_SUCCESS) {
716         string extractCmd = getFullFileArchiveExtractCommand(
717         		this->fileArchiveExtractCommand,
718         		this->fileArchiveExtractCommandParameters,
719         		destRootArchiveFolder,
720         		destRootArchiveFolder + techtreeName.first + this->fileArchiveExtension);
721 
722 		static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
723 	    MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
724 	    this->getProgressMutex()->setOwnerId(mutexOwnerId);
725 	    if(this->pCBObject != NULL) {
726 	    	this->shellCommandCallbackUserData = techtreeName.first;
727 	        this->pCBObject->FTPClient_CallbackEvent(
728 	        		techtreeName.first,
729 	        		ftp_cct_ExtractProgress,
730 	        		make_pair(ftp_crt_SUCCESS,"extracting"),NULL);
731 	    }
732 	    safeMutex.ReleaseLock();
733 
734         if(executeShellCommand(extractCmd,this->fileArchiveExtractCommandSuccessResult,this) == false) {
735         	result.first = ftp_crt_FAIL;
736         	result.second = "failed to extract archive!";
737         }
738     }
739 
740     return result;
741 
742 }
743 
getScenarioFromServer(pair<string,string> fileName)744 void FTPClientThread::getScenarioFromServer(pair<string,string> fileName) {
745 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
746 	bool findArchive = executeShellCommand(
747 			this->fileArchiveExtractCommand,
748 			this->fileArchiveExtractCommandSuccessResult);
749 	if(findArchive == true) {
750 		result = getScenarioInternalFromServer(fileName);
751 	}
752 
753 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
754     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
755     this->getProgressMutex()->setOwnerId(mutexOwnerId);
756     if(this->pCBObject != NULL) {
757         this->pCBObject->FTPClient_CallbackEvent(
758         		fileName.first,
759         		ftp_cct_Scenario,
760         		result,
761         		NULL);
762     }
763 }
764 
getScenarioInternalFromServer(pair<string,string> fileName)765 pair<FTP_Client_ResultType,string>  FTPClientThread::getScenarioInternalFromServer(pair<string,string> fileName) {
766     // Root folder for the techtree
767     string destRootFolder = this->scenariosPath.second;
768 	endPathWithSlash(destRootFolder);
769 	string destRootArchiveFolder = destRootFolder;
770 	destRootFolder += fileName.first;
771 	endPathWithSlash(destRootFolder);
772 
773 	string destFile = this->scenariosPath.second;
774 	endPathWithSlash(destFile);
775     destFile += fileName.first;
776     string destFileSaveAs = destFile + this->fileArchiveExtension;
777     endPathWithSlash(destFile);
778 
779     string remotePath = fileName.first + this->fileArchiveExtension;
780     if(fileName.second != "") {
781     	remotePath = fileName.second;
782     }
783 
784     pair<FTP_Client_ResultType,string> result = getFileFromServer(ftp_cct_Scenario,
785     		fileName, remotePath, destFileSaveAs, "", "");
786 
787     // Extract the archive
788     if(result.first == ftp_crt_SUCCESS) {
789         string extractCmd = getFullFileArchiveExtractCommand(
790         		this->fileArchiveExtractCommand,
791         		this->fileArchiveExtractCommandParameters,
792         		destRootArchiveFolder,
793         		destRootArchiveFolder + fileName.first + this->fileArchiveExtension);
794 
795 		static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
796 	    MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
797 	    this->getProgressMutex()->setOwnerId(mutexOwnerId);
798 	    if(this->pCBObject != NULL) {
799 	    	this->shellCommandCallbackUserData = fileName.first;
800 	        this->pCBObject->FTPClient_CallbackEvent(
801 	        		fileName.first,
802 	        		ftp_cct_ExtractProgress,
803 	        		make_pair(ftp_crt_SUCCESS,"extracting"),NULL);
804 	    }
805 	    safeMutex.ReleaseLock();
806 
807         if(executeShellCommand(extractCmd,this->fileArchiveExtractCommandSuccessResult,this) == false) {
808         	result.first = ftp_crt_FAIL;
809         	result.second = "failed to extract archive!";
810         }
811     }
812 
813     return result;
814 
815 }
816 
getFileFromServer(pair<string,string> fileName)817 void FTPClientThread::getFileFromServer(pair<string,string> fileName) {
818 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
819 
820 	bool findArchive = true;
821 	string ext = extractExtension(fileName.first);
822 	if(("." + ext) == this->fileArchiveExtension) {
823 		findArchive = executeShellCommand(
824 				this->fileArchiveExtractCommand,
825 				this->fileArchiveExtractCommandSuccessResult);
826 	}
827 	if(findArchive == true) {
828 		result = getFileInternalFromServer(fileName);
829 	}
830 
831 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
832     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
833     this->getProgressMutex()->setOwnerId(mutexOwnerId);
834     if(this->pCBObject != NULL) {
835         this->pCBObject->FTPClient_CallbackEvent(fileName.first,ftp_cct_File,result,NULL);
836     }
837 }
838 
getFileInternalFromServer(pair<string,string> fileName)839 pair<FTP_Client_ResultType,string>  FTPClientThread::getFileInternalFromServer(pair<string,string> fileName) {
840 	string destFile = fileName.first;
841 	string destFileSaveAs = fileName.first;
842 
843 	string remotePath = fileName.second;
844 
845     pair<FTP_Client_ResultType,string> result = getFileFromServer(ftp_cct_File,
846     		fileName,remotePath, destFileSaveAs, "", "");
847 
848     //printf("Got file [%s] result.first = %d\n",destFileSaveAs.c_str(),result.first);
849 
850     // Extract the archive
851     if(result.first == ftp_crt_SUCCESS) {
852     	string ext = extractExtension(destFileSaveAs);
853     	if(("." + ext) == fileArchiveExtension) {
854     		string destRootArchiveFolder = extractDirectoryPathFromFile(destFileSaveAs);
855 			string extractCmd = getFullFileArchiveExtractCommand(
856 					this->fileArchiveExtractCommand,
857 					this->fileArchiveExtractCommandParameters,
858 					destRootArchiveFolder,
859 					destFileSaveAs);
860 
861 			if(executeShellCommand(extractCmd,this->fileArchiveExtractCommandSuccessResult) == false) {
862 				result.first = ftp_crt_FAIL;
863 				result.second = "failed to extract archive!";
864 			}
865     	}
866     }
867 
868     return result;
869 }
870 
getTempFileFromServer(pair<string,string> fileName)871 void FTPClientThread::getTempFileFromServer(pair<string,string> fileName) {
872 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
873 
874 	bool findArchive = true;
875 	string ext = extractExtension(fileName.first);
876 	if(("." + ext) == this->fileArchiveExtension) {
877 		findArchive = executeShellCommand(
878 				this->fileArchiveExtractCommand,
879 				this->fileArchiveExtractCommandSuccessResult);
880 	}
881 	if(findArchive == true) {
882 		result = getTempFileInternalFromServer(fileName);
883 	}
884 
885 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
886     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
887     this->getProgressMutex()->setOwnerId(mutexOwnerId);
888     if(this->pCBObject != NULL) {
889         this->pCBObject->FTPClient_CallbackEvent(fileName.first,ftp_cct_TempFile,result,NULL);
890     }
891 }
892 
getTempFileInternalFromServer(pair<string,string> fileName)893 pair<FTP_Client_ResultType,string>  FTPClientThread::getTempFileInternalFromServer(pair<string,string> fileName) {
894 	string destFile = fileName.first;
895 	//string destFileSaveAs = fileName.first;
896     string destFileSaveAs = tempFilesPath;
897 
898 	endPathWithSlash(destFileSaveAs);
899 	destFileSaveAs += fileName.first;
900 
901 	string remotePath = fileName.second;
902 
903 	//printf("First [%s] Second [%s]\n",fileName.first.c_str(),fileName.second.c_str());
904 	pair<FTP_Client_ResultType,string> result;
905 	if(StartsWith(remotePath,"http://")) {
906 		result = getFileFromServer(ftp_cct_TempFile, fileName,remotePath, destFileSaveAs, "", "");
907 	}
908 	else {
909 		fileName.second = "";
910 		result = getFileFromServer(ftp_cct_TempFile,fileName,remotePath, destFileSaveAs, FTP_TEMPFILES_USERNAME, FTP_COMMON_PASSWORD);
911 	}
912 
913     //printf("Got temp file [%s] result.first = %d\n",destFileSaveAs.c_str(),result.first);
914 
915     // Extract the archive
916     if(result.first == ftp_crt_SUCCESS) {
917     	string ext = extractExtension(destFileSaveAs);
918     	if(("." + ext) == fileArchiveExtension) {
919     		string destRootArchiveFolder = extractDirectoryPathFromFile(destFileSaveAs);
920 			string extractCmd = getFullFileArchiveExtractCommand(
921 					this->fileArchiveExtractCommand,
922 					this->fileArchiveExtractCommandParameters,
923 					destRootArchiveFolder,
924 					destFileSaveAs);
925 
926 			if(executeShellCommand(extractCmd,this->fileArchiveExtractCommandSuccessResult) == false) {
927 				result.first = ftp_crt_FAIL;
928 				result.second = "failed to extract archive!";
929 			}
930     	}
931     }
932 
933     return result;
934 }
935 
getFileFromServer(FTP_Client_CallbackType downloadType,pair<string,string> fileNameTitle,string remotePath,string destFileSaveAs,string ftpUser,string ftpUserPassword,vector<string> * wantDirListOnly)936 pair<FTP_Client_ResultType,string>  FTPClientThread::getFileFromServer(FTP_Client_CallbackType downloadType,
937 		pair<string,string> fileNameTitle,
938 		string remotePath, string destFileSaveAs,
939 		string ftpUser, string ftpUserPassword, vector <string> *wantDirListOnly) {
940 	pair<FTP_Client_ResultType,string> result = make_pair(ftp_crt_FAIL,"");
941     if(wantDirListOnly) {
942     	(*wantDirListOnly).clear();
943     }
944     string destRootFolder = extractDirectoryPathFromFile(destFileSaveAs);
945     bool pathCreated = false;
946     if(isdir(destRootFolder.c_str()) == false) {
947     	createDirectoryPaths(destRootFolder);
948     	pathCreated = true;
949     }
950 
951     bool wantDirList = (wantDirListOnly != NULL);
952 
953     if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread about to try to RETR into [%s] wantDirList = %d\n",destFileSaveAs.c_str(),wantDirList);
954     if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread about to try to RETR into [%s] wantDirList = %d\n",destFileSaveAs.c_str(),wantDirList);
955 
956     struct FtpFile ftpfile = {
957     	fileNameTitle.first.c_str(),
958     	destFileSaveAs.c_str(), // name to store the file as if successful
959     	NULL,
960         NULL,
961         this,
962         "",
963         false,
964         downloadType
965     };
966 
967     CURL *curl = SystemFlags::initHTTP();
968     if(curl) {
969         ftpfile.stream = NULL;
970 
971         char szBuf[8096]="";
972         if(fileNameTitle.second != "") {
973         	snprintf(szBuf,8096,"%s",fileNameTitle.second.c_str());
974         	curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
975         }
976         else {
977         	snprintf(szBuf,8096,"ftp://%s:%s@%s:%d/%s",ftpUser.c_str(),ftpUserPassword.c_str(),serverUrl.c_str(),portNumber,remotePath.c_str());
978         }
979 
980         //printf("===> Getting ftp file: %s\n",szBuf);
981 
982         curl_easy_setopt(curl, CURLOPT_URL,szBuf);
983         curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
984 
985         // turn on wildcard matching
986         //curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L);
987 
988         // callback is called before download of concrete file started
989         //curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_comming);
990         // callback is called after data from the file have been transferred
991         //curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded);
992 
993         //curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &ftpfile);
994         curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
995 
996         // Define our callback to get called when there's data to be written
997         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
998         // Set a pointer to our struct to pass to the callback
999         curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
1000 
1001         if(wantDirListOnly) {
1002         	curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1);
1003         }
1004         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
1005         curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, file_progress);
1006         curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &ftpfile);
1007 
1008         // Max 10 minutes to transfer
1009         //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 600);
1010         // Max 60 minutes to transfer
1011         curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3600L);
1012         curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, 120L);
1013 
1014         // Switch on full protocol/debug output
1015         if(SystemFlags::VERBOSE_MODE_ENABLED) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
1016 
1017         CURLcode res = curl_easy_perform(curl);
1018 
1019         if(res != CURLE_OK) {
1020         	result.second = curl_easy_strerror(res);
1021             // we failed
1022             printf("curl FAILED with: %d [%s] attempting to remove folder contents [%s] szBuf [%s] ftpfile.isValidXfer = %d, pathCreated = %d\n", res,curl_easy_strerror(res),destRootFolder.c_str(),szBuf,ftpfile.isValidXfer,pathCreated);
1023             if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"curl FAILED with: %d [%s] attempting to remove folder contents [%s] szBuf [%s] ftpfile.isValidXfer = %d, pathCreated = %d\n", res,curl_easy_strerror(res),destRootFolder.c_str(),szBuf,ftpfile.isValidXfer,pathCreated);
1024 
1025             if(res == CURLE_PARTIAL_FILE || ftpfile.isValidXfer == true) {
1026         	    result.first = ftp_crt_PARTIALFAIL;
1027             }
1028             else if(res == CURLE_COULDNT_CONNECT) {
1029           	  result.first = ftp_crt_HOST_NOT_ACCEPTING;
1030             }
1031 
1032 
1033             if(destRootFolder != "") {
1034             	if(pathCreated == true) {
1035             		removeFolder(destRootFolder);
1036             	}
1037             	else {
1038             		removeFile(destFileSaveAs);
1039             	}
1040             }
1041         }
1042         else {
1043             result.first = ftp_crt_SUCCESS;
1044 
1045             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] result.first = %d wantDirListOnly = %p\n",__FILE__,__FUNCTION__,__LINE__,result.first,wantDirListOnly);
1046 
1047             if(wantDirListOnly) {
1048                 if(ftpfile.stream) {
1049                     fclose(ftpfile.stream);
1050                     ftpfile.stream = NULL;
1051                 }
1052 
1053 #ifdef WIN32
1054 				FILE *fp = _wfopen(utf8_decode(destFileSaveAs).c_str(), L"rt");
1055 #else
1056                 FILE *fp = fopen(destFileSaveAs.c_str(), "rt");
1057 #endif
1058                 if(fp != NULL) {
1059                 	char szBuf[4096]="";
1060                 	while(feof(fp) == false) {
1061             			if(fgets( szBuf, 4095, fp) != NULL) {
1062             				string item = szBuf;
1063             				replaceAll(item,"\n","");
1064             				replaceAll(item,"\r","");
1065             				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Got [%s]\n",item.c_str());
1066             				(*wantDirListOnly).push_back(item);
1067             			}
1068                 	}
1069                 	fclose(fp);
1070                 }
1071             }
1072         }
1073 
1074         SystemFlags::cleanupHTTP(&curl);
1075     }
1076 
1077     if(ftpfile.stream) {
1078         fclose(ftpfile.stream);
1079         ftpfile.stream = NULL;
1080     }
1081 
1082     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] result.first = %d\n",__FILE__,__FUNCTION__,__LINE__,result.first);
1083 
1084     return result;
1085 }
1086 
getCallBackObject()1087 FTPClientCallbackInterface * FTPClientThread::getCallBackObject() {
1088 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
1089     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
1090     this->getProgressMutex()->setOwnerId(mutexOwnerId);
1091     return pCBObject;
1092 }
1093 
setCallBackObject(FTPClientCallbackInterface * value)1094 void FTPClientThread::setCallBackObject(FTPClientCallbackInterface *value) {
1095 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
1096     MutexSafeWrapper safeMutex(this->getProgressMutex(),mutexOwnerId);
1097     this->getProgressMutex()->setOwnerId(mutexOwnerId);
1098     pCBObject = value;
1099 }
1100 
ShellCommandOutput_CallbackEvent(string cmd,char * output,void * userdata)1101 void FTPClientThread::ShellCommandOutput_CallbackEvent(string cmd,char *output,void *userdata) {
1102     if(this->pCBObject != NULL) {
1103 
1104     	string &itemName = *static_cast<string *>(userdata);
1105         this->pCBObject->FTPClient_CallbackEvent(
1106         		itemName,
1107         		ftp_cct_ExtractProgress,
1108         		make_pair(ftp_crt_SUCCESS,"extracting"),
1109         		output);
1110     }
1111 }
1112 
getShellCommandOutput_UserData(string cmd)1113 void * FTPClientThread::getShellCommandOutput_UserData(string cmd) {
1114 	return &shellCommandCallbackUserData;
1115 }
1116 
execute()1117 void FTPClientThread::execute() {
1118     {
1119         RunningStatusSafeWrapper runningStatus(this);
1120         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1121 
1122         if(getQuitStatus() == true) {
1123             return;
1124         }
1125 
1126         if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread is running\n");
1127         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"FTP Client thread is running\n");
1128 
1129         try	{
1130             while(this->getQuitStatus() == false) {
1131             	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
1132                 MutexSafeWrapper safeMutex(&mutexMapFileList,mutexOwnerId);
1133                 mutexMapFileList.setOwnerId(mutexOwnerId);
1134                 if(mapFileList.size() > 0) {
1135                     pair<string,string> mapFilename = mapFileList[0];
1136                     mapFileList.erase(mapFileList.begin() + 0);
1137                     safeMutex.ReleaseLock();
1138 
1139                     getMapFromServer(mapFilename);
1140                 }
1141                 else {
1142                     safeMutex.ReleaseLock();
1143                 }
1144 
1145                 if(this->getQuitStatus() == true) {
1146                     break;
1147                 }
1148 
1149                 static string mutexOwnerId2 = string(__FILE__) + string("_") + intToStr(__LINE__);
1150                 MutexSafeWrapper safeMutex2(&mutexTilesetList,mutexOwnerId2);
1151                 mutexTilesetList.setOwnerId(mutexOwnerId2);
1152                 if(tilesetList.size() > 0) {
1153                 	pair<string,string> tileset = tilesetList[0];
1154                     tilesetList.erase(tilesetList.begin() + 0);
1155                     safeMutex2.ReleaseLock();
1156 
1157                     getTilesetFromServer(tileset);
1158                 }
1159                 else {
1160                     safeMutex2.ReleaseLock();
1161                 }
1162 
1163                 static string mutexOwnerId3 = string(__FILE__) + string("_") + intToStr(__LINE__);
1164                 MutexSafeWrapper safeMutex3(&mutexTechtreeList,mutexOwnerId3);
1165                 mutexTechtreeList.setOwnerId(mutexOwnerId3);
1166                 if(techtreeList.size() > 0) {
1167                 	pair<string,string> techtree = techtreeList[0];
1168                     techtreeList.erase(techtreeList.begin() + 0);
1169                     safeMutex3.ReleaseLock();
1170 
1171                     getTechtreeFromServer(techtree);
1172                 }
1173                 else {
1174                     safeMutex3.ReleaseLock();
1175                 }
1176 
1177                 static string mutexOwnerId4 = string(__FILE__) + string("_") + intToStr(__LINE__);
1178                 MutexSafeWrapper safeMutex4(&mutexScenarioList,mutexOwnerId4);
1179                 mutexScenarioList.setOwnerId(mutexOwnerId4);
1180                 if(scenarioList.size() > 0) {
1181                 	pair<string,string> file = scenarioList[0];
1182                 	scenarioList.erase(scenarioList.begin() + 0);
1183                     safeMutex4.ReleaseLock();
1184 
1185                     getScenarioFromServer(file);
1186                 }
1187                 else {
1188                     safeMutex4.ReleaseLock();
1189                 }
1190 
1191                 static string mutexOwnerId5 = string(__FILE__) + string("_") + intToStr(__LINE__);
1192                 MutexSafeWrapper safeMutex5(&mutexFileList,mutexOwnerId5);
1193                 mutexFileList.setOwnerId(mutexOwnerId5);
1194                 if(fileList.size() > 0) {
1195                 	pair<string,string> file = fileList[0];
1196                 	fileList.erase(fileList.begin() + 0);
1197                     safeMutex5.ReleaseLock();
1198 
1199                     getFileFromServer(file);
1200                 }
1201                 else {
1202                     safeMutex5.ReleaseLock();
1203                 }
1204 
1205                 static string mutexOwnerId6 = string(__FILE__) + string("_") + intToStr(__LINE__);
1206                 MutexSafeWrapper safeMutex6(&mutexTempFileList,mutexOwnerId6);
1207                 mutexTempFileList.setOwnerId(mutexOwnerId6);
1208                 if(tempFileList.size() > 0) {
1209                 	pair<string,string> file = tempFileList[0];
1210                 	tempFileList.erase(tempFileList.begin() + 0);
1211                     safeMutex6.ReleaseLock();
1212 
1213                     getTempFileFromServer(file);
1214                 }
1215                 else {
1216                     safeMutex6.ReleaseLock();
1217                 }
1218 
1219                 if(this->getQuitStatus() == false) {
1220                     sleep(25);
1221                 }
1222             }
1223 
1224             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client exiting!\n");
1225             if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client exiting!\n");
1226         }
1227         catch(const exception &ex) {
1228             SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1229             if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1230         }
1231         catch(...) {
1232             SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] UNKNOWN Error\n",__FILE__,__FUNCTION__,__LINE__);
1233             if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] unknown error\n",__FILE__,__FUNCTION__,__LINE__);
1234         }
1235 
1236         if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] FTP Client thread is exiting\n",__FILE__,__FUNCTION__,__LINE__);
1237     }
1238 
1239     // Delete ourself when the thread is done (no other actions can happen after this
1240     // such as the mutex which modifies the running status of this method
1241     deleteSelfIfRequired();
1242 }
1243 
1244 }}//end namespace
1245