// ==========================================================================
// Author: Yee Hsu
// Date: 9/5/2008
// File: FTP.cpp
//
// Desc: FTP wrapper that does simple FTP API calls. Now we have an FTP
// object we can call and use to make FTP connections, transfer
// files, and download files using this simple API
// ==========================================================================
#include "stdafx.h"
#include "CFTP.h"
// ==========================================================================
// Identifier: CFTP()
//
// Description: CFTP Constructor
// ==========================================================================
CFTP::CFTP()
{
this->sFileContents = "";
this->hInternet = NULL;
this->hConnection = NULL;
this->hFileHandle = NULL;
this->dwFileSize = NULL;
this->lpThreadId = 0L;
this->lpThreadExitCode = 0L;
this->lpThreadIdleMSec = 60000L; // Default Timeout: 1 minute
this->bFTPSuccess = false;
}
// ==========================================================================
// Identifier: CFTP()
//
// Description: CFTP Destructor
// ==========================================================================
CFTP::~CFTP()
{
this->sFileContents = "";
this->hInternet = NULL;
this->hConnection = NULL;
this->hFileHandle = NULL;
this->dwFileSize = NULL;
}
// ==========================================================================
// Identifier: InitFTPInfo()
//
// Description: Initialize FTP info
// ==========================================================================
void CFTP::InitFTPInfo(const FTPInfo ftpInfo)
{
this->ftpInfo = ftpInfo;
}
// ==========================================================================
// Identifier: InternetOpen()
//
// Description: Open an FTP connection
// ==========================================================================
bool CFTP::InternetOpen(void)
{
hInternet = ::InternetOpen("FTP Connection", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if( !hInternet )
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: InternetClose()
//
// Description: Close an FTP connection
// ==========================================================================
bool CFTP::InternetClose(void)
{
if( hFileHandle )
InternetCloseHandle( hFileHandle );
if( hConnection )
InternetCloseHandle( hConnection );
if( hInternet )
InternetCloseHandle( hInternet );
return true;
}
// ==========================================================================
// Identifier: FtpConnect()
//
// Description: Connection to an FTP session
// ==========================================================================
bool CFTP::FtpConnect(void)
{
hConnection = ::InternetConnect(hInternet, ftpInfo.lpszServerName, INTERNET_DEFAULT_FTP_PORT, ftpInfo.lpszUserName, ftpInfo.lpszPassword, INTERNET_SERVICE_FTP, NULL, NULL);
if( !hConnection )
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: FtpSetCurrentDirectory()
//
// Description: Sets the current directory for an FTP connection
// ==========================================================================
bool CFTP::FtpSetCurrentDirectory(void)
{
if ( !::FtpSetCurrentDirectory( hConnection, ftpInfo.lpszDirectory) )
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: FtpFindFirstFile()
//
// Description: Finds the first file
// ==========================================================================
bool CFTP::FtpFindFirstFile(void)
{
WIN32_FIND_DATA lpFindFileDate = {0};
hFileHandle = ::FtpFindFirstFile(hConnection, ftpInfo.lpszRemoteFile, &lpFindFileDate, INTERNET_FLAG_RELOAD, NULL );
if ( !hFileHandle )
{
InternetClose();
return false;
}
if (!FileTimeToSystemTime( &lpFindFileDate.ftLastWriteTime, &stSysTime ))
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: FtpOpenFile()
//
// Description: Opens the file
// ==========================================================================
bool CFTP::FtpOpenFile(void)
{
hFileHandle = ::FtpOpenFile( hConnection, ftpInfo.lpszRemoteFile, GENERIC_READ, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD, NULL );
if ( !hFileHandle )
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: FtpReadFile()
//
// Description: Reads the file
// ==========================================================================
bool CFTP::FtpReadFile(void)
{
bool bRet;
DWORD dwFileSizeHigh;
char* szBuffer = NULL;
szBuffer = new char[this->dwFileSize + 1]; // Extra character reserved for terminating NULL character
memset(szBuffer, 0, this->dwFileSize + 1); // init the array with \0
this->sFileContents.clear();
if ( InternetReadFile( hFileHandle, ( LPVOID ) szBuffer, this->dwFileSize, &dwFileSizeHigh ) == FALSE )
{
InternetClose();
bRet = false;
}
else
{
this->sFileContents = szBuffer;
bRet = true;
}
if (szBuffer)
delete szBuffer;
return bRet;
}
// ==========================================================================
// Identifier: FtpGetFileSize()
//
// Description: Gets the file size
// ==========================================================================
bool CFTP::FtpGetFileSize(void)
{
DWORD dwFileSizeHigh;
dwFileSize = ::FtpGetFileSize( hFileHandle, &dwFileSizeHigh );
return true;
}
// ==========================================================================
// Identifier: FtpPutFile()
//
// Description: Uploads a file
// ==========================================================================
bool CFTP::FtpPutFile(void)
{
if( !::FtpPutFile( hConnection, ftpInfo.lpszLocalFile, ftpInfo.lpszRemoteFile, FTP_TRANSFER_TYPE_BINARY, NULL ) )
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: FtpGetFile()
//
// Description: Downloads a file
// ==========================================================================
bool CFTP::FtpGetFile(void)
{
if( !::FtpGetFile( hConnection, ftpInfo.lpszRemoteFile, ftpInfo.lpszLocalFile, FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY, NULL ) )
{
InternetClose();
return false;
}
return true;
}
// ==========================================================================
// Identifier: UploadFile()
//
// Description: Uploads a file
// ==========================================================================
bool CFTP::UploadFile(const FTPInfo ftpInfo)
{
this->InitFTPInfo(ftpInfo);
if (!this->InternetOpen())
return false;
if (!this->InternetConnect())
return false;
if (!this->FtpSetCurrentDirectory())
return false;
if (!this->FtpPutFile())
return false;
this->InternetClose();
return true;
}
// ==========================================================================
// Identifier: DownloadFile()
//
// Description: Downloads a file
// ==========================================================================
bool CFTP::DownloadFile(const FTPInfo ftpInfo)
{
this->InitFTPInfo(ftpInfo);
if (!this->InternetOpen())
return false;
if (!this->InternetConnect())
return false;
if (!this->FtpSetCurrentDirectory())
return false;
if (!this->FtpGetFile())
return false;
this->InternetClose();
return true;
}
// ==========================================================================
// Identifier: DownloadFile()
//
// Description: Gets a file size
// ==========================================================================
bool CFTP::GetFileSize(const FTPInfo ftpInfo, int& nFileSize)
{
this->InitFTPInfo(ftpInfo);
if (!this->InternetOpen())
return false;
if (!this->InternetConnect())
return false;
if (!this->FtpSetCurrentDirectory())
return false;
if (!this->FtpOpenFile())
return false;
if (!this->FtpGetFileSize())
return false;
nFileSize = this->dwFileSize;
this->InternetClose();
return true;
}
// ==========================================================================
// Identifier: GetFileDate()
//
// Description: Gets a file date
// ==========================================================================
bool CFTP::GetFileDate(const FTPInfo ftpInfo, SYSTEMTIME& stSysTime)
{
this->InitFTPInfo(ftpInfo);
if (!this->InternetOpen())
return false;
if (!this->InternetConnect())
return false;
if (!this->FtpSetCurrentDirectory())
return false;
if (!this->FtpFindFirstFile())
return false;
stSysTime = this->stSysTime;
this->InternetClose();
return true;
}
// ==========================================================================
// Identifier: ReadFileContents()
//
// Description: Reads the contents of a file
// ==========================================================================
bool CFTP::ReadFileContents(const FTPInfo ftpInfo, std::string& sFileContents)
{
this->InitFTPInfo(ftpInfo);
if (!this->InternetOpen())
return false;
if (!this->InternetConnect())
return false;
if (!this->FtpSetCurrentDirectory())
return false;
if (!this->FtpOpenFile())
return false;
if (!this->FtpGetFileSize())
return false;
if (!this->FtpReadFile())
return false;
sFileContents = this->sFileContents;
this->InternetClose();
return true;
}
// ==========================================================================
// Identifier: GetFileInfo()
//
// Description: Gets information about a file
// ==========================================================================
bool CFTP::GetFileInfo(const FTPInfo ftpInfo, std::string& sFileContents, SYSTEMTIME& stSysTime, int* nFileSize)
{
this->InitFTPInfo(ftpInfo);
if (!this->InternetOpen())
return false;
if (!this->InternetConnect())
return false;
if (!this->FtpSetCurrentDirectory())
return false;
if (!this->FtpFindFirstFile())
return false;
if (!this->FtpOpenFile())
return false;
if (!this->FtpGetFileSize())
return false;
if (!this->FtpReadFile())
return false;
if (nFileSize)
*nFileSize = this->dwFileSize;
stSysTime = this->stSysTime;
sFileContents = this->sFileContents;
this->InternetClose();
return true;
}
/* *************************************** Threaded FTP Codes Here ****************************************** */
// ==========================================================================
// Identifier: InternetConnect()
//
// Description: Makes an FTP connection
// ==========================================================================
bool CFTP::InternetConnect(void)
{
this->bFTPSuccess = false;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadStart, this, 0, &lpThreadId);
if ( WaitForSingleObject(hThread, lpThreadIdleMSec * FTP_TIMEOUT_MINUTES) == WAIT_TIMEOUT)
{
this->InternetClose();
WaitForSingleObject(hThread, lpThreadIdleMSec);
this->bFTPSuccess = false;
}
CloseHandle(hThread);
return this->bFTPSuccess; // returns TRUE (in mult-threaded code) when FTP request success
}
// ==========================================================================
// Identifier: ThreadFTPRequestTimeOut()
//
// Description: Threaded FTP connection
// ==========================================================================
bool WINAPI CFTP::ThreadFTPRequestTimeOut()
{
bFTPSuccess = false;
hConnection = ::InternetConnect(hInternet, ftpInfo.lpszServerName, INTERNET_DEFAULT_FTP_PORT, ftpInfo.lpszUserName, ftpInfo.lpszPassword, INTERNET_SERVICE_FTP, NULL, NULL);
if ( !hConnection )
InternetClose();
else
this->bFTPSuccess = true;
ExitThread(lpThreadExitCode);
return bFTPSuccess;
}
// ==========================================================================
// Identifier: ThreadStart()
//
// Description: Starts a FTP connection in its own thread
// ==========================================================================
DWORD CFTP::ThreadStart(CFTP* pFTP)
{
pFTP->ThreadFTPRequestTimeOut();
return 0;
}