// This file is part of Glest // // Copyright (C) 2018 The Glest team // // Glest is a fork of MegaGlest // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see #include "miniftpclient.h" #include "util.h" #include "platform_common.h" #include #include #include #include "conversion.h" #include "platform_util.h" using namespace Shared::Util; using namespace Shared::PlatformCommon; namespace Shared { namespace PlatformCommon { static const char *FTP_MAPS_CUSTOM_USERNAME = "maps_custom"; static const char *FTP_MAPS_USERNAME = "maps"; static const char *FTP_TILESETS_CUSTOM_USERNAME = "tilesets_custom"; static const char *FTP_TILESETS_USERNAME = "tilesets"; static const char *FTP_TECHTREES_CUSTOM_USERNAME = "techtrees_custom"; static const char *FTP_TECHTREES_USERNAME = "techtrees"; static const char *FTP_TEMPFILES_USERNAME = "temp"; static const char *FTP_COMMON_PASSWORD = "mg_ftp_server"; /* * This is an example showing how to get a single file from an FTP server. * It delays the actual destination file creation until the first write * callback so that it won't create an empty file in case the remote file * doesn't exist or something else fails. */ struct FtpFile { const char *itemName; const char *filename; const char *filepath; FILE *stream; FTPClientThread *ftpServer; string currentFilename; bool isValidXfer; FTP_Client_CallbackType downloadType; }; static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) { struct FtpFile *out = (struct FtpFile *)stream; string fullFilePath = ""; if (out != NULL && out->filepath != NULL) { fullFilePath = out->filepath; } if (out != NULL && out->filename != NULL) { fullFilePath += out->filename; } if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread writing to file [%s]\n", fullFilePath.c_str()); //printf ("===> FTP Client thread writing to file [%s]\n",fullFilePath.c_str()); // Abort file xfer and delete partial file if (out && out->ftpServer && out->ftpServer->getQuitStatus() == true) { if (out->stream) { fclose(out->stream); out->stream = NULL; } if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread CANCELLED, deleting file for writing [%s]\n", fullFilePath.c_str()); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client thread CANCELLED, deleting file for writing [%s]\n", fullFilePath.c_str()); removeFile(fullFilePath); return 0; } if (out && out->stream == NULL) { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread opening file for writing [%s]\n", fullFilePath.c_str()); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client thread opening file for writing [%s]\n", fullFilePath.c_str()); /* open file for writing */ #ifdef WIN32 out->stream = _wfopen(utf8_decode(fullFilePath).c_str(), L"wb"); #else out->stream = fopen(fullFilePath.c_str(), "wb"); #endif if (out->stream == NULL) { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread FAILED to open file for writing [%s]\n", fullFilePath.c_str()); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client thread FAILED to open file for writing [%s]\n", fullFilePath.c_str()); SystemFlags::OutputDebug(SystemFlags::debugError, "===> FTP Client thread FAILED to open file for writing [%s]\n", fullFilePath.c_str()); return 0; /* failure, can't open file to write */ } out->isValidXfer = true; } else if (out == NULL) { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> #2 FTP Client thread FAILED to open file for writing [%s]\n", fullFilePath.c_str()); 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()); SystemFlags::OutputDebug(SystemFlags::debugError, "===> #2 FTP Client thread FAILED to open file for writing [%s]\n", fullFilePath.c_str()); return 0; /* failure, can't open file to write */ } size_t result = fwrite(buffer, size, nmemb, out->stream); if (result != nmemb) { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread FAILED to write data chunk to file [%s] nmemb = " SIZE_T_SPECIFIER ", result = " SIZE_T_SPECIFIER "\n", fullFilePath.c_str(), nmemb, result); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client thread FAILED to write data chunk to file [%s] nmemb = " SIZE_T_SPECIFIER ", result = " SIZE_T_SPECIFIER "\n", fullFilePath.c_str(), nmemb, result); SystemFlags::OutputDebug(SystemFlags::debugError, "===> FTP Client thread FAILED to write data chunk to file [%s] nmemb = " SIZE_T_SPECIFIER ", result = " SIZE_T_SPECIFIER "\n", fullFilePath.c_str(), nmemb, result); //return -1; /* failure, can't open file to write */ } return result; } /* static long file_is_comming(struct curl_fileinfo *finfo,void *data,int remains) { struct FtpFile *out=(struct FtpFile *)data; string rootFilePath = ""; string fullFilePath = ""; if(out != NULL && out->filepath != NULL) { rootFilePath = out->filepath; } if(out != NULL && out->filename != NULL) { fullFilePath = rootFilePath + finfo->filename; } 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); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread file_is_comming: remains: [%3d] filename: [%s] size: [%10luB] ", remains, finfo->filename,(unsigned long)finfo->size); if(out != NULL) { //out->currentFilename = finfo->filename; out->currentFilename = fullFilePath; if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" current filename: [%s] ", fullFilePath.c_str()); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"current filename: [%s] ", fullFilePath.c_str()); } switch(finfo->filetype) { case CURLFILETYPE_DIRECTORY: if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" DIR (creating [%s%s])\n",rootFilePath.c_str(),finfo->filename); SystemFlags::OutputDebug(SystemFlags::debugNetwork," DIR (creating [%s%s])\n",rootFilePath.c_str(),finfo->filename); rootFilePath += finfo->filename; createDirectoryPaths(rootFilePath.c_str()); break; case CURLFILETYPE_FILE: if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" FILE "); SystemFlags::OutputDebug(SystemFlags::debugNetwork," FILE "); break; default: if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" OTHER\n"); SystemFlags::OutputDebug(SystemFlags::debugNetwork," OTHER\n"); break; } if(finfo->filetype == CURLFILETYPE_FILE) { // do not transfer files >= 50B //if(finfo->size > 50) { // printf("SKIPPED\n"); // return CURL_CHUNK_BGN_FUNC_SKIP; //} if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" opening file [%s] ", fullFilePath.c_str()); SystemFlags::OutputDebug(SystemFlags::debugNetwork," opening file [%s] ", fullFilePath.c_str()); out->stream = fopen(fullFilePath.c_str(), "wb"); if(out->stream == NULL) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf ("===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str()); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"===> FTP Client thread FAILED to open file for writing [%s]\n",fullFilePath.c_str()); return CURL_CHUNK_BGN_FUNC_FAIL; } } out->isValidXfer = true; return CURL_CHUNK_BGN_FUNC_OK; } static long file_is_downloaded(void *data) { struct FtpFile *out=(struct FtpFile *)data; if(out->stream) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("DOWNLOAD COMPLETE!\n"); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"DOWNLOAD COMPLETE!\n"); fclose(out->stream); out->stream = NULL; } return CURL_CHUNK_END_FUNC_OK; } */ int file_progress(struct FtpFile *out, double download_total, double download_now, double upload_total, double upload_now) { //if(SystemFlags::VERBOSE_MODE_ENABLED) printf(" download progress [%f][%f][%f][%f] ",download_total,download_now,upload_total,upload_now); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, " download progress [%f][%f][%f][%f] ", download_total, download_now, upload_total, upload_now); if (out != NULL && out->ftpServer != NULL && out->ftpServer->getCallBackObject() != NULL) { if (out->ftpServer->getQuitStatus() == true) { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread CANCELLED\n"); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client thread CANCELLED\n"); return -1; } FTPClientCallbackInterface::FtpProgressStats stats; stats.download_total = download_total; stats.download_now = download_now; stats.upload_total = upload_total; stats.upload_now = upload_now; stats.currentFilename = out->currentFilename; stats.downloadType = out->downloadType; static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(out->ftpServer->getProgressMutex(), mutexOwnerId); out->ftpServer->getProgressMutex()->setOwnerId(mutexOwnerId); out->ftpServer->getCallBackObject()->FTPClient_CallbackEvent( out->itemName, ftp_cct_DownloadProgress, make_pair(ftp_crt_SUCCESS, ""), &stats); } return 0; } FTPClientThread::FTPClientThread(int portNumber, string serverUrl, std::pair mapsPath, std::pair tilesetsPath, std::pair techtreesPath, std::pair scenariosPath, FTPClientCallbackInterface *pCBObject, string fileArchiveExtension, string fileArchiveExtractCommand, string fileArchiveExtractCommandParameters, int fileArchiveExtractCommandSuccessResult, string tempFilesPath) : BaseThread() { uniqueID = "FTPClientThread"; this->portNumber = portNumber; this->serverUrl = serverUrl; this->mapsPath = mapsPath; this->tilesetsPath = tilesetsPath; this->techtreesPath = techtreesPath; this->scenariosPath = scenariosPath; this->pCBObject = pCBObject; this->shellCommandCallbackUserData = ""; this->fileArchiveExtension = fileArchiveExtension; this->fileArchiveExtractCommand = fileArchiveExtractCommand; this->fileArchiveExtractCommandParameters = fileArchiveExtractCommandParameters; this->fileArchiveExtractCommandSuccessResult = fileArchiveExtractCommandSuccessResult; this->tempFilesPath = tempFilesPath; 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()); } void FTPClientThread::signalQuit() { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client: signalQuit\n"); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client: signalQuit\n"); BaseThread::signalQuit(); } bool FTPClientThread::shutdownAndWait() { if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client: shutdownAndWait\n"); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client: shutdownAndWait\n"); signalQuit(); return BaseThread::shutdownAndWait(); } pair FTPClientThread::getMapFromServer(pair mapFileName, string ftpUser, string ftpUserPassword) { pair result = make_pair(ftp_crt_FAIL, ""); string destFileExt = ""; string destFile = this->mapsPath.second; endPathWithSlash(destFile); destFile += mapFileName.first; if (mapFileName.second == "") { if (EndsWith(destFile, ".mgm") == false && EndsWith(destFile, ".gbm") == false) { destFileExt = ".mgm"; destFile += destFileExt; } } if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread about to try to RETR into [%s]\n", destFile.c_str()); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client thread about to try to RETR into [%s]\n", destFile.c_str()); struct FtpFile ftpfile = { NULL, destFile.c_str(), /* name to store the file as if succesful */ NULL, NULL, this, "", false, ftp_cct_Map }; CURL *curl = SystemFlags::initHTTP(); if (curl) { ftpfile.stream = NULL; curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); char szBuf[8096] = ""; if (mapFileName.second != "") { snprintf(szBuf, 8096, "%s", mapFileName.second.c_str()); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); } else { 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()); } curl_easy_setopt(curl, CURLOPT_URL, szBuf); curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L); /* Define our callback to get called when there's data to be written */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); /* Set a pointer to our struct to pass to the callback */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); // Max 10 minutes to transfer //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 600); // Max 60 minutes to transfer curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3600L); curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, 120L); /* Switch on full protocol/debug output */ if (SystemFlags::VERBOSE_MODE_ENABLED) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { result.second = curl_easy_strerror(res); // we failed printf("curl FAILED with: %d [%s] szBuf [%s]\n", res, curl_easy_strerror(res), szBuf); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "curl FAILED with: %d [%s] szBuf [%s]\n", res, curl_easy_strerror(res), szBuf); if (res == CURLE_PARTIAL_FILE) { result.first = ftp_crt_PARTIALFAIL; } else if (res == CURLE_COULDNT_CONNECT) { result.first = ftp_crt_HOST_NOT_ACCEPTING; } } else { result.first = ftp_crt_SUCCESS; } SystemFlags::cleanupHTTP(&curl); } if (ftpfile.stream) { fclose(ftpfile.stream); ftpfile.stream = NULL; } if (result.first != ftp_crt_SUCCESS) { removeFile(destFile); } return result; } void FTPClientThread::getMapFromServer(pair mapFileName) { pair result = make_pair(ftp_crt_FAIL, ""); if (mapFileName.second != "") { result = getMapFromServer(mapFileName, "", ""); } else { pair findMapFileName = mapFileName; findMapFileName.first += +".mgm"; result = getMapFromServer(findMapFileName, FTP_MAPS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD); if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { findMapFileName = mapFileName; findMapFileName.first += +".gbm"; result = getMapFromServer(findMapFileName, FTP_MAPS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD); if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { findMapFileName = mapFileName; findMapFileName.first += +".mgm"; result = getMapFromServer(findMapFileName, FTP_MAPS_USERNAME, FTP_COMMON_PASSWORD); if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { findMapFileName = mapFileName; findMapFileName.first += +".mgm"; result = getMapFromServer(findMapFileName, FTP_MAPS_USERNAME, FTP_COMMON_PASSWORD); if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { findMapFileName = mapFileName; findMapFileName.first += +".gbm"; result = getMapFromServer(findMapFileName, FTP_MAPS_USERNAME, FTP_COMMON_PASSWORD); } } } } } static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->pCBObject->FTPClient_CallbackEvent( mapFileName.first, ftp_cct_Map, result, NULL); } } void FTPClientThread::addMapToRequests(string mapFilename, string URL) { std::pair item = make_pair(mapFilename, URL); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexMapFileList, mutexOwnerId); mutexMapFileList.setOwnerId(mutexOwnerId); if (std::find(mapFileList.begin(), mapFileList.end(), item) == mapFileList.end()) { mapFileList.push_back(item); } } void FTPClientThread::addTilesetToRequests(string tileSetName, string URL) { std::pair item = make_pair(tileSetName, URL); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexTilesetList, mutexOwnerId); mutexTilesetList.setOwnerId(mutexOwnerId); if (std::find(tilesetList.begin(), tilesetList.end(), item) == tilesetList.end()) { tilesetList.push_back(item); } } void FTPClientThread::addTechtreeToRequests(string techtreeName, string URL) { std::pair item = make_pair(techtreeName, URL); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexTechtreeList, mutexOwnerId); mutexTechtreeList.setOwnerId(mutexOwnerId); if (std::find(techtreeList.begin(), techtreeList.end(), item) == techtreeList.end()) { techtreeList.push_back(item); } } void FTPClientThread::addScenarioToRequests(string fileName, string URL) { std::pair item = make_pair(fileName, URL); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexScenarioList, mutexOwnerId); mutexScenarioList.setOwnerId(mutexOwnerId); if (std::find(scenarioList.begin(), scenarioList.end(), item) == scenarioList.end()) { scenarioList.push_back(item); } } void FTPClientThread::addFileToRequests(string fileName, string URL) { std::pair item = make_pair(fileName, URL); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexFileList, mutexOwnerId); mutexFileList.setOwnerId(mutexOwnerId); if (std::find(fileList.begin(), fileList.end(), item) == fileList.end()) { fileList.push_back(item); } } void FTPClientThread::addTempFileToRequests(string fileName, string URL) { std::pair item = make_pair(fileName, URL); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexTempFileList, mutexOwnerId); mutexTempFileList.setOwnerId(mutexOwnerId); if (std::find(tempFileList.begin(), tempFileList.end(), item) == tempFileList.end()) { tempFileList.push_back(item); } } void FTPClientThread::getTilesetFromServer(pair tileSetName) { bool findArchive = executeShellCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandSuccessResult); pair result = make_pair(ftp_crt_FAIL, ""); if (findArchive == true) { if (tileSetName.second != "") { //result = getTilesetFromServer(tileSetName, "", "", "", findArchive); result = getTilesetFromServer(tileSetName, "", "", "", true); } else { //result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, findArchive); result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, true); if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { //if(findArchive == true) { //result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, false); result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_CUSTOM_USERNAME, FTP_COMMON_PASSWORD, true); //} if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { // result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_USERNAME, FTP_COMMON_PASSWORD, findArchive); result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_USERNAME, FTP_COMMON_PASSWORD, true); // if(findArchive == true) { // result = getTilesetFromServer(tileSetName, "", FTP_TILESETS_USERNAME, FTP_COMMON_PASSWORD, false); // } } } } } static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->pCBObject->FTPClient_CallbackEvent( tileSetName.first, ftp_cct_Tileset, result, NULL); } } pair FTPClientThread::getTilesetFromServer( pair tileSetName, string tileSetNameSubfolder, string ftpUser, string ftpUserPassword, bool findArchive) { string destFileSaveAsNewFile = ""; string destFileSaveAs = ""; string remotePath = ""; bool getFolderContents = false; vector wantDirListOnly; if (tileSetNameSubfolder == "") { if (findArchive == true) { destFileSaveAs = this->tilesetsPath.second; endPathWithSlash(destFileSaveAs); destFileSaveAs += tileSetName.first + this->fileArchiveExtension; if (tileSetName.second != "") { remotePath = tileSetName.second; } else { remotePath = tileSetName.first + this->fileArchiveExtension; } } else { getFolderContents = true; remotePath = tileSetName.first + "/"; destFileSaveAs = this->tilesetsPath.second; endPathWithSlash(destFileSaveAs); destFileSaveAs += tileSetName.first; destFileSaveAsNewFile = destFileSaveAs; endPathWithSlash(destFileSaveAsNewFile); destFileSaveAs += ".tmp"; } } else { getFolderContents = true; remotePath = tileSetName.first + "/" + tileSetNameSubfolder + "/"; destFileSaveAs = this->tilesetsPath.second; endPathWithSlash(destFileSaveAs); destFileSaveAs += tileSetName.first; endPathWithSlash(destFileSaveAs); destFileSaveAs += tileSetNameSubfolder; destFileSaveAsNewFile = destFileSaveAs; endPathWithSlash(destFileSaveAsNewFile); destFileSaveAs += ".tmp"; } vector *pWantDirListOnly = NULL; if (getFolderContents == true) { pWantDirListOnly = &wantDirListOnly; } 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); pair result = getFileFromServer( ftp_cct_Tileset, tileSetName, remotePath, destFileSaveAs, ftpUser, ftpUserPassword, pWantDirListOnly); 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); // Extract the archive if (result.first == ftp_crt_SUCCESS) { if (findArchive == true) { string destRootArchiveFolder = this->tilesetsPath.second; endPathWithSlash(destRootArchiveFolder); string extractCmd = getFullFileArchiveExtractCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandParameters, destRootArchiveFolder, destRootArchiveFolder + tileSetName.first + this->fileArchiveExtension); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->shellCommandCallbackUserData = tileSetName.first; this->pCBObject->FTPClient_CallbackEvent( tileSetName.first, ftp_cct_ExtractProgress, make_pair(ftp_crt_SUCCESS, "extracting"), NULL); } safeMutex.ReleaseLock(); if (executeShellCommand(extractCmd, this->fileArchiveExtractCommandSuccessResult, this) == false) { result.first = ftp_crt_FAIL; result.second = "failed to extract archive!"; } return result; } else { if (getFolderContents == true) { removeFile(destFileSaveAs); for (unsigned int i = 0; i < wantDirListOnly.size(); ++i) { string fileFromList = wantDirListOnly[i]; if (SystemFlags::VERBOSE_MODE_ENABLED) printf("fileFromList [%s] i [%u]\n", fileFromList.c_str(), i); if (fileFromList != "models" && fileFromList != "textures" && fileFromList != "sounds") { result = getFileFromServer(ftp_cct_Tileset, tileSetName, remotePath + fileFromList, destFileSaveAsNewFile + fileFromList, ftpUser, ftpUserPassword); if (result.first != ftp_crt_SUCCESS) { break; } } else { result = getTilesetFromServer(tileSetName, fileFromList, ftpUser, ftpUserPassword, findArchive); if (result.first != ftp_crt_SUCCESS) { break; } } } } } } if (result.first != ftp_crt_SUCCESS && findArchive == false) { string destRootFolder = this->tilesetsPath.second; endPathWithSlash(destRootFolder); destRootFolder += tileSetName.first; endPathWithSlash(destRootFolder); removeFolder(destRootFolder); } return result; } void FTPClientThread::getTechtreeFromServer(pair techtreeName) { pair result = make_pair(ftp_crt_FAIL, ""); bool findArchive = executeShellCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandSuccessResult); if (findArchive == true) { if (techtreeName.second != "") { result = getTechtreeFromServer(techtreeName, "", ""); } else { result = getTechtreeFromServer(techtreeName, FTP_TECHTREES_CUSTOM_USERNAME, FTP_COMMON_PASSWORD); if (result.first == ftp_crt_FAIL && this->getQuitStatus() == false) { result = getTechtreeFromServer(techtreeName, FTP_TECHTREES_USERNAME, FTP_COMMON_PASSWORD); } } } static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->pCBObject->FTPClient_CallbackEvent( techtreeName.first, ftp_cct_Techtree, result, NULL); } } pair FTPClientThread::getTechtreeFromServer(pair techtreeName, string ftpUser, string ftpUserPassword) { // Root folder for the techtree string destRootFolder = this->techtreesPath.second; endPathWithSlash(destRootFolder); string destRootArchiveFolder = destRootFolder; destRootFolder += techtreeName.first; endPathWithSlash(destRootFolder); string destFile = this->techtreesPath.second; endPathWithSlash(destFile); destFile += techtreeName.first; string destFileSaveAs = destFile + this->fileArchiveExtension; endPathWithSlash(destFile); string remotePath = techtreeName.first + this->fileArchiveExtension; if (techtreeName.second != "") { remotePath = techtreeName.second; } pair result = getFileFromServer(ftp_cct_Techtree, techtreeName, remotePath, destFileSaveAs, ftpUser, ftpUserPassword); // Extract the archive if (result.first == ftp_crt_SUCCESS) { string extractCmd = getFullFileArchiveExtractCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandParameters, destRootArchiveFolder, destRootArchiveFolder + techtreeName.first + this->fileArchiveExtension); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->shellCommandCallbackUserData = techtreeName.first; this->pCBObject->FTPClient_CallbackEvent( techtreeName.first, ftp_cct_ExtractProgress, make_pair(ftp_crt_SUCCESS, "extracting"), NULL); } safeMutex.ReleaseLock(); if (executeShellCommand(extractCmd, this->fileArchiveExtractCommandSuccessResult, this) == false) { result.first = ftp_crt_FAIL; result.second = "failed to extract archive!"; } } return result; } void FTPClientThread::getScenarioFromServer(pair fileName) { pair result = make_pair(ftp_crt_FAIL, ""); bool findArchive = executeShellCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandSuccessResult); if (findArchive == true) { result = getScenarioInternalFromServer(fileName); } static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->pCBObject->FTPClient_CallbackEvent( fileName.first, ftp_cct_Scenario, result, NULL); } } pair FTPClientThread::getScenarioInternalFromServer(pair fileName) { // Root folder for the techtree string destRootFolder = this->scenariosPath.second; endPathWithSlash(destRootFolder); string destRootArchiveFolder = destRootFolder; destRootFolder += fileName.first; endPathWithSlash(destRootFolder); string destFile = this->scenariosPath.second; endPathWithSlash(destFile); destFile += fileName.first; string destFileSaveAs = destFile + this->fileArchiveExtension; endPathWithSlash(destFile); string remotePath = fileName.first + this->fileArchiveExtension; if (fileName.second != "") { remotePath = fileName.second; } pair result = getFileFromServer(ftp_cct_Scenario, fileName, remotePath, destFileSaveAs, "", ""); // Extract the archive if (result.first == ftp_crt_SUCCESS) { string extractCmd = getFullFileArchiveExtractCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandParameters, destRootArchiveFolder, destRootArchiveFolder + fileName.first + this->fileArchiveExtension); static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->shellCommandCallbackUserData = fileName.first; this->pCBObject->FTPClient_CallbackEvent( fileName.first, ftp_cct_ExtractProgress, make_pair(ftp_crt_SUCCESS, "extracting"), NULL); } safeMutex.ReleaseLock(); if (executeShellCommand(extractCmd, this->fileArchiveExtractCommandSuccessResult, this) == false) { result.first = ftp_crt_FAIL; result.second = "failed to extract archive!"; } } return result; } void FTPClientThread::getFileFromServer(pair fileName) { pair result = make_pair(ftp_crt_FAIL, ""); bool findArchive = true; string ext = extractExtension(fileName.first); if (("." + ext) == this->fileArchiveExtension) { findArchive = executeShellCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandSuccessResult); } if (findArchive == true) { result = getFileInternalFromServer(fileName); } static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->pCBObject->FTPClient_CallbackEvent(fileName.first, ftp_cct_File, result, NULL); } } pair FTPClientThread::getFileInternalFromServer(pair fileName) { string destFile = fileName.first; string destFileSaveAs = fileName.first; string remotePath = fileName.second; pair result = getFileFromServer(ftp_cct_File, fileName, remotePath, destFileSaveAs, "", ""); //printf("Got file [%s] result.first = %d\n",destFileSaveAs.c_str(),result.first); // Extract the archive if (result.first == ftp_crt_SUCCESS) { string ext = extractExtension(destFileSaveAs); if (("." + ext) == fileArchiveExtension) { string destRootArchiveFolder = extractDirectoryPathFromFile(destFileSaveAs); string extractCmd = getFullFileArchiveExtractCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandParameters, destRootArchiveFolder, destFileSaveAs); if (executeShellCommand(extractCmd, this->fileArchiveExtractCommandSuccessResult) == false) { result.first = ftp_crt_FAIL; result.second = "failed to extract archive!"; } } } return result; } void FTPClientThread::getTempFileFromServer(pair fileName) { pair result = make_pair(ftp_crt_FAIL, ""); bool findArchive = true; string ext = extractExtension(fileName.first); if (("." + ext) == this->fileArchiveExtension) { findArchive = executeShellCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandSuccessResult); } if (findArchive == true) { result = getTempFileInternalFromServer(fileName); } static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); if (this->pCBObject != NULL) { this->pCBObject->FTPClient_CallbackEvent(fileName.first, ftp_cct_TempFile, result, NULL); } } pair FTPClientThread::getTempFileInternalFromServer(pair fileName) { string destFile = fileName.first; //string destFileSaveAs = fileName.first; string destFileSaveAs = tempFilesPath; endPathWithSlash(destFileSaveAs); destFileSaveAs += fileName.first; string remotePath = fileName.second; //printf("First [%s] Second [%s]\n",fileName.first.c_str(),fileName.second.c_str()); pair result; if (StartsWith(remotePath, "http://")) { result = getFileFromServer(ftp_cct_TempFile, fileName, remotePath, destFileSaveAs, "", ""); } else { fileName.second = ""; result = getFileFromServer(ftp_cct_TempFile, fileName, remotePath, destFileSaveAs, FTP_TEMPFILES_USERNAME, FTP_COMMON_PASSWORD); } //printf("Got temp file [%s] result.first = %d\n",destFileSaveAs.c_str(),result.first); // Extract the archive if (result.first == ftp_crt_SUCCESS) { string ext = extractExtension(destFileSaveAs); if (("." + ext) == fileArchiveExtension) { string destRootArchiveFolder = extractDirectoryPathFromFile(destFileSaveAs); string extractCmd = getFullFileArchiveExtractCommand( this->fileArchiveExtractCommand, this->fileArchiveExtractCommandParameters, destRootArchiveFolder, destFileSaveAs); if (executeShellCommand(extractCmd, this->fileArchiveExtractCommandSuccessResult) == false) { result.first = ftp_crt_FAIL; result.second = "failed to extract archive!"; } } } return result; } pair FTPClientThread::getFileFromServer(FTP_Client_CallbackType downloadType, pair fileNameTitle, string remotePath, string destFileSaveAs, string ftpUser, string ftpUserPassword, vector *wantDirListOnly) { pair result = make_pair(ftp_crt_FAIL, ""); if (wantDirListOnly) { (*wantDirListOnly).clear(); } string destRootFolder = extractDirectoryPathFromFile(destFileSaveAs); bool pathCreated = false; if (isdir(destRootFolder.c_str()) == false) { createDirectoryPaths(destRootFolder); pathCreated = true; } bool wantDirList = (wantDirListOnly != NULL); if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread about to try to RETR into [%s] wantDirList = %d\n", destFileSaveAs.c_str(), wantDirList); 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); struct FtpFile ftpfile = { fileNameTitle.first.c_str(), destFileSaveAs.c_str(), // name to store the file as if successful NULL, NULL, this, "", false, downloadType }; CURL *curl = SystemFlags::initHTTP(); if (curl) { ftpfile.stream = NULL; curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); char szBuf[8096] = ""; if (fileNameTitle.second != "") { snprintf(szBuf, 8096, "%s", fileNameTitle.second.c_str()); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); } else { snprintf(szBuf, 8096, "ftp://%s:%s@%s:%d/%s", ftpUser.c_str(), ftpUserPassword.c_str(), serverUrl.c_str(), portNumber, remotePath.c_str()); } //printf("===> Getting ftp file: %s\n",szBuf); curl_easy_setopt(curl, CURLOPT_URL, szBuf); curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L); // turn on wildcard matching //curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L); // callback is called before download of concrete file started //curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_comming); // callback is called after data from the file have been transferred //curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded); //curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &ftpfile); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); // Define our callback to get called when there's data to be written curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); // Set a pointer to our struct to pass to the callback curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); if (wantDirListOnly) { curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1); } curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, file_progress); curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &ftpfile); // Max 10 minutes to transfer //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 600); // Max 60 minutes to transfer curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3600L); curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, 120L); // Switch on full protocol/debug output if (SystemFlags::VERBOSE_MODE_ENABLED) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { result.second = curl_easy_strerror(res); // we failed 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); 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); if (res == CURLE_PARTIAL_FILE || ftpfile.isValidXfer == true) { result.first = ftp_crt_PARTIALFAIL; } else if (res == CURLE_COULDNT_CONNECT) { result.first = ftp_crt_HOST_NOT_ACCEPTING; } if (destRootFolder != "") { if (pathCreated == true) { removeFolder(destRootFolder); } else { removeFile(destFileSaveAs); } } } else { result.first = ftp_crt_SUCCESS; if (SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] result.first = %d wantDirListOnly = %p\n", __FILE__, __FUNCTION__, __LINE__, result.first, wantDirListOnly); if (wantDirListOnly) { if (ftpfile.stream) { fclose(ftpfile.stream); ftpfile.stream = NULL; } #ifdef WIN32 FILE *fp = _wfopen(utf8_decode(destFileSaveAs).c_str(), L"rt"); #else FILE *fp = fopen(destFileSaveAs.c_str(), "rt"); #endif if (fp != NULL) { char szBuf[4096] = ""; while (feof(fp) == false) { if (fgets(szBuf, 4095, fp) != NULL) { string item = szBuf; replaceAll(item, "\n", ""); replaceAll(item, "\r", ""); if (SystemFlags::VERBOSE_MODE_ENABLED) printf("Got [%s]\n", item.c_str()); (*wantDirListOnly).push_back(item); } } fclose(fp); } } } SystemFlags::cleanupHTTP(&curl); } if (ftpfile.stream) { fclose(ftpfile.stream); ftpfile.stream = NULL; } if (SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] result.first = %d\n", __FILE__, __FUNCTION__, __LINE__, result.first); return result; } FTPClientCallbackInterface * FTPClientThread::getCallBackObject() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); return pCBObject; } void FTPClientThread::setCallBackObject(FTPClientCallbackInterface *value) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(this->getProgressMutex(), mutexOwnerId); this->getProgressMutex()->setOwnerId(mutexOwnerId); pCBObject = value; } void FTPClientThread::ShellCommandOutput_CallbackEvent(string cmd, char *output, void *userdata) { if (this->pCBObject != NULL) { string &itemName = *static_cast(userdata); this->pCBObject->FTPClient_CallbackEvent( itemName, ftp_cct_ExtractProgress, make_pair(ftp_crt_SUCCESS, "extracting"), output); } } void * FTPClientThread::getShellCommandOutput_UserData(string cmd) { return &shellCommandCallbackUserData; } void FTPClientThread::execute() { { RunningStatusSafeWrapper runningStatus(this); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d]\n", __FILE__, __FUNCTION__, __LINE__); if (getQuitStatus() == true) { return; } if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client thread is running\n"); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "FTP Client thread is running\n"); try { while (this->getQuitStatus() == false) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(&mutexMapFileList, mutexOwnerId); mutexMapFileList.setOwnerId(mutexOwnerId); if (mapFileList.size() > 0) { pair mapFilename = mapFileList[0]; mapFileList.erase(mapFileList.begin() + 0); safeMutex.ReleaseLock(); getMapFromServer(mapFilename); } else { safeMutex.ReleaseLock(); } if (this->getQuitStatus() == true) { break; } static string mutexOwnerId2 = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex2(&mutexTilesetList, mutexOwnerId2); mutexTilesetList.setOwnerId(mutexOwnerId2); if (tilesetList.size() > 0) { pair tileset = tilesetList[0]; tilesetList.erase(tilesetList.begin() + 0); safeMutex2.ReleaseLock(); getTilesetFromServer(tileset); } else { safeMutex2.ReleaseLock(); } static string mutexOwnerId3 = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex3(&mutexTechtreeList, mutexOwnerId3); mutexTechtreeList.setOwnerId(mutexOwnerId3); if (techtreeList.size() > 0) { pair techtree = techtreeList[0]; techtreeList.erase(techtreeList.begin() + 0); safeMutex3.ReleaseLock(); getTechtreeFromServer(techtree); } else { safeMutex3.ReleaseLock(); } static string mutexOwnerId4 = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex4(&mutexScenarioList, mutexOwnerId4); mutexScenarioList.setOwnerId(mutexOwnerId4); if (scenarioList.size() > 0) { pair file = scenarioList[0]; scenarioList.erase(scenarioList.begin() + 0); safeMutex4.ReleaseLock(); getScenarioFromServer(file); } else { safeMutex4.ReleaseLock(); } static string mutexOwnerId5 = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex5(&mutexFileList, mutexOwnerId5); mutexFileList.setOwnerId(mutexOwnerId5); if (fileList.size() > 0) { pair file = fileList[0]; fileList.erase(fileList.begin() + 0); safeMutex5.ReleaseLock(); getFileFromServer(file); } else { safeMutex5.ReleaseLock(); } static string mutexOwnerId6 = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex6(&mutexTempFileList, mutexOwnerId6); mutexTempFileList.setOwnerId(mutexOwnerId6); if (tempFileList.size() > 0) { pair file = tempFileList[0]; tempFileList.erase(tempFileList.begin() + 0); safeMutex6.ReleaseLock(); getTempFileFromServer(file); } else { safeMutex6.ReleaseLock(); } if (this->getQuitStatus() == false) { sleep(25); } } if (SystemFlags::VERBOSE_MODE_ENABLED) printf("===> FTP Client exiting!\n"); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "===> FTP Client exiting!\n"); } catch (const exception &ex) { SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d] Error [%s]\n", __FILE__, __FUNCTION__, __LINE__, ex.what()); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] error [%s]\n", __FILE__, __FUNCTION__, __LINE__, ex.what()); } catch (...) { SystemFlags::OutputDebug(SystemFlags::debugError, "In [%s::%s Line: %d] UNKNOWN Error\n", __FILE__, __FUNCTION__, __LINE__); if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] unknown error\n", __FILE__, __FUNCTION__, __LINE__); } if (SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork, "In [%s::%s Line: %d] FTP Client thread is exiting\n", __FILE__, __FUNCTION__, __LINE__); } // Delete ourself when the thread is done (no other actions can happen after this // such as the mutex which modifies the running status of this method deleteSelfIfRequired(); } } } //end namespace