Index: src/ch/UpdateChecker.cpp =================================================================== diff -u -r5057e08b0cc064972abeb94a488e5f12d9db14a0 -r8068e0c351055554340ac9755d1bc846893bf2b8 --- src/ch/UpdateChecker.cpp (.../UpdateChecker.cpp) (revision 5057e08b0cc064972abeb94a488e5f12d9db14a0) +++ src/ch/UpdateChecker.cpp (.../UpdateChecker.cpp) (revision 8068e0c351055554340ac9755d1bc846893bf2b8) @@ -22,431 +22,25 @@ // ============================================================================ #include "stdafx.h" #include "UpdateChecker.h" +#include "UpdateResponse.h" #include -#include +#include "../libchcore/TWin32ErrorFormatter.h" #include "../common/version.h" -#include "../libicpf/cfg.h" -#include "../libicpf/exception.h" -#include "../libicpf/circ_buffer.h" +#include -// timeout used with waiting for events (avoiding hangs) -#define FORCE_TIMEOUT 60000 - // ============================================================================ -/// CAsyncHttpFile::CAsyncHttpFile -/// @date 2009/04/18 -/// -/// @brief Constructs the CAsyncHttpFile object. -// ============================================================================ -CAsyncHttpFile::CAsyncHttpFile() : - m_hInternet(NULL), - m_hOpenUrl(NULL), - m_dwExpectedState(0), - m_hFinishedEvent(NULL), - m_dwError(ERROR_SUCCESS) -{ - memset(&m_internetBuffers, 0, sizeof(INTERNET_BUFFERS)); - - m_tOpenRequest.pHttpFile = this; - m_tOpenRequest.eOperationType = CONTEXT_REQUEST::eInternetOpenUrl; - - m_tReadRequest.pHttpFile = this; - m_tReadRequest.eOperationType = CONTEXT_REQUEST::eInternetReadFileEx; -} - -// ============================================================================ -/// CAsyncHttpFile::~CAsyncHttpFile -/// @date 2009/04/18 -/// -/// @brief Destructs the CASyncHttpFile object. -// ============================================================================ -CAsyncHttpFile::~CAsyncHttpFile() -{ - Close(); -} - -// ============================================================================ -/// CAsyncHttpFile::Open -/// @date 2009/04/18 -/// -/// @brief Opens the specified internet address (starts those operations). -/// @param[in] pszPath Url to be opened (full path to file). -/// @return S_OK if opened, S_FALSE if wait for result is needed, E_* for errors. -// ============================================================================ -HRESULT CAsyncHttpFile::Open(const tchar_t* pszPath) -{ - if(!pszPath) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_INVALIDARG; - } - - if(m_hInternet || m_hFinishedEvent) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - // reset error code - SetErrorCode(ERROR_SUCCESS); - - // create event - m_hFinishedEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); - if(!m_hFinishedEvent) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - m_hInternet = ::InternetOpen(_T(PRODUCT_NAME), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC); - if(!m_hInternet) - { - SetErrorCode(GetLastError()); - - ::CloseHandle(m_hFinishedEvent); - m_hFinishedEvent = NULL; - - return E_FAIL; - } - - if(::InternetSetStatusCallback(m_hInternet, (INTERNET_STATUS_CALLBACK)&CAsyncHttpFile::InternetStatusCallback) == INTERNET_INVALID_STATUS_CALLBACK) - { - SetErrorCode(GetLastError()); - - ::InternetCloseHandle(m_hInternet); - ::CloseHandle(m_hFinishedEvent); - - m_hFinishedEvent = NULL; - return E_FAIL; - } - - m_dwExpectedState = INTERNET_STATUS_REQUEST_COMPLETE; - HINTERNET hOpenUrl = ::InternetOpenUrl(m_hInternet, pszPath, NULL, 0, INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, (DWORD_PTR)&m_tOpenRequest); - if(!hOpenUrl) - { - SetErrorCode(::GetLastError()); - if(GetErrorCode() != ERROR_IO_PENDING) - { - ::InternetSetStatusCallback(m_hInternet, NULL); - ::InternetCloseHandle(m_hInternet); - ::CloseHandle(m_hFinishedEvent); - - m_hInternet = NULL; - m_hFinishedEvent = NULL; - m_dwExpectedState = 0; - - return E_FAIL; - } - } - else - { - m_dwExpectedState = 0; // everything has been completed - ::SetEvent(m_hFinishedEvent); - } - - return hOpenUrl ? S_OK : S_FALSE; -} - -// ============================================================================ -/// CAsyncHttpFile::GetFileSize -/// @date 2009/04/18 -/// -/// @brief Retrieves the size of file opened with CAsyncHttpFile::Open() -// (if such information exists in http headers). -/// @param[out] stSize Receives the size of file (receives 65536 if http headers -/// did not contain the information). -/// @return Result of the operation. -// ============================================================================ -HRESULT CAsyncHttpFile::GetFileSize(size_t& stSize) -{ - if(!m_hInternet || !m_hOpenUrl) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - DWORD dwContentLengthSize = sizeof(DWORD); - if(!HttpQueryInfo(m_hOpenUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &stSize, &dwContentLengthSize, NULL) || stSize == 0 || stSize > 1*1024UL*1024UL) - { - stSize = 65536; // safe fallback - return S_FALSE; - } - - return S_OK; -} - -// ============================================================================ -/// CAsyncHttpFile::RequestData -/// @date 2009/04/18 -/// -/// @brief Requests the data from already opened url. -/// @param[in] pBuffer Buffer for the data. -/// @param[in] stSize Buffer size. -/// @return S_OK if completed, S_FALSE if needs waiting, E_* on error. -// ============================================================================ -HRESULT CAsyncHttpFile::RequestData(void* pBuffer, size_t stSize) -{ - if(!pBuffer) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_INVALIDARG; - } - if(!m_hInternet || !m_hOpenUrl || !m_hFinishedEvent) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - SetErrorCode(ERROR_SUCCESS); - - if(!::ResetEvent(m_hFinishedEvent)) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - memset(&m_internetBuffers, 0, sizeof(INTERNET_BUFFERS)); - m_internetBuffers.dwStructSize = sizeof(INTERNET_BUFFERS); - m_internetBuffers.dwBufferLength = (DWORD)stSize; - m_internetBuffers.dwBufferTotal = (DWORD)stSize; - m_internetBuffers.lpvBuffer = pBuffer; - - m_dwExpectedState = INTERNET_STATUS_REQUEST_COMPLETE; - if(!::InternetReadFileEx(m_hOpenUrl, &m_internetBuffers, IRF_NO_WAIT, (DWORD_PTR)&m_tReadRequest)) - { - SetErrorCode(::GetLastError()); - if(GetErrorCode() == ERROR_IO_PENDING) - return S_FALSE; - else - return E_FAIL; - } - - if(!::SetEvent(m_hFinishedEvent)) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - return S_OK; -} - -// ============================================================================ -/// CAsyncHttpFile::RetrieveRequestedData -/// @date 2009/04/18 -/// -/// @brief Retrieves the size of data retrieved. -/// @param[out] stSize Receives the size of data read from file. -/// @return Result of the operation. -// ============================================================================ -HRESULT CAsyncHttpFile::GetRetrievedDataSize(size_t& stSize) -{ - if(!m_hInternet) - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - - stSize = m_internetBuffers.dwBufferLength; - return S_OK; -} - -// ============================================================================ -/// CAsyncHttpFile::Close -/// @date 2009/04/18 -/// -/// @brief Closes the file. -/// @return Result of the operation. -// ============================================================================ -HRESULT CAsyncHttpFile::Close() -{ - SetErrorCode(ERROR_SUCCESS); - if(m_hOpenUrl) - { - m_dwExpectedState = INTERNET_STATUS_CLOSING_CONNECTION; - if(!::InternetCloseHandle(m_hOpenUrl)) - { - SetErrorCode(::GetLastError()); - if(GetErrorCode() == ERROR_IO_PENDING) - return S_FALSE; - else - { - SetErrorCode(ERROR_INTERNAL_ERROR); - return E_FAIL; - } - } - - // if closing url handle succeeded, we close internet here, if not - // then a separate call to close need to be performed. - m_dwExpectedState = 0; - SetUrlHandle(NULL); - ::InternetCloseHandle(m_hInternet); - } - - if(m_hFinishedEvent) - { - ::CloseHandle(m_hFinishedEvent); - m_hFinishedEvent = NULL; - } - - return S_OK; -} - -// ============================================================================ -/// CAsyncHttpFile::GetResult -/// @date 2009/04/18 -/// -/// @brief Retrieves the last call result (blocking call). -/// @return Result of the last call. -// ============================================================================ -CAsyncHttpFile::EWaitResult CAsyncHttpFile::GetResult() -{ - HANDLE hHandles[] = { m_hFinishedEvent }; - DWORD dwEffect = WaitForMultipleObjects(1, hHandles, FALSE, 0); - if(dwEffect == WAIT_OBJECT_0 + 0 || dwEffect == WAIT_ABANDONED_0 + 0) - return GetErrorCode() == ERROR_SUCCESS ? CAsyncHttpFile::eFinished : CAsyncHttpFile::eError; - else - return CAsyncHttpFile::ePending; -} - -// ============================================================================ -/// CAsyncHttpFile::WaitForResult -/// @date 2009/04/18 -/// -/// @brief Waits for the result with additional 'kill' event. -/// @param[in] hKillEvent Event handle that would break waiting for result. -/// @return Result of waiting. -// ============================================================================ -CAsyncHttpFile::EWaitResult CAsyncHttpFile::WaitForResult(HANDLE hKillEvent) -{ - HANDLE hHandles[] = { hKillEvent, m_hFinishedEvent }; - DWORD dwEffect = WaitForMultipleObjects(2, hHandles, FALSE, FORCE_TIMEOUT); - if(dwEffect == 0xffffffff) - { - SetErrorCode(::GetLastError()); - return CAsyncHttpFile::eError; - } - else if(dwEffect == WAIT_OBJECT_0 + 0 || dwEffect == WAIT_ABANDONED_0 + 0) - return CAsyncHttpFile::eKilled; - else if(dwEffect == WAIT_OBJECT_0 + 1 || dwEffect == WAIT_ABANDONED_0 + 1) - return GetErrorCode() == ERROR_SUCCESS ? CAsyncHttpFile::eFinished : CAsyncHttpFile::eError; - else - return CAsyncHttpFile::eTimeout; -} - -// ============================================================================ -/// CAsyncHttpFile::InternetStatusCallback -/// @date 2009/04/18 -/// -/// @brief Callback for use with internet API. -/// @param[in] hInternet Internet handle. -/// @param[in] dwContext Context value. -/// @param[in] dwInternetStatus Internet status. -/// @param[in] lpvStatusInformation Additional status information. -/// @param[in] dwStatusInformationLength Length of lpvStatusInformation. -// ============================================================================ -void CALLBACK CAsyncHttpFile::InternetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) -{ - CONTEXT_REQUEST* pRequest = (CONTEXT_REQUEST*)dwContext; - BOOST_ASSERT(pRequest && pRequest->pHttpFile); - if(!pRequest || !pRequest->pHttpFile) - return; - - CString strMsg; - strMsg.Format(_T("[CAsyncHttpFile::InternetStatusCallback] hInternet: %p, dwContext: %lu (operation: %lu), dwInternetStatus: %lu, lpvStatusInformation: %p, dwStatusInformationLength: %lu\n"), - hInternet, dwContext, pRequest ? pRequest->eOperationType : CONTEXT_REQUEST::eNone, dwInternetStatus, lpvStatusInformation, dwStatusInformationLength); - LOG_DEBUG(strMsg); - - switch(dwInternetStatus) - { - case INTERNET_STATUS_HANDLE_CREATED: - { - INTERNET_ASYNC_RESULT* pRes = (INTERNET_ASYNC_RESULT*)lpvStatusInformation; - pRequest->pHttpFile->SetUrlHandle((HINTERNET)(pRes->dwResult)); - break; - } - case INTERNET_STATUS_RESPONSE_RECEIVED: - { - ATLTRACE(_T("INTERNET_STATUS_RESPONSE_RECEIVED; received %lu bytes."), *(DWORD*)lpvStatusInformation); - break; - } - case INTERNET_STATUS_REQUEST_COMPLETE: - { - INTERNET_ASYNC_RESULT* pResult = (INTERNET_ASYNC_RESULT*)lpvStatusInformation; - pRequest->pHttpFile->SetErrorCode(pResult->dwError); - break; - } - case INTERNET_STATUS_CLOSING_CONNECTION: - { - pRequest->pHttpFile->SetUrlHandle(NULL); - break; - } - case INTERNET_STATUS_CONNECTION_CLOSED: - { - break; - } - default: - TRACE(_T("[CAsyncHttpFile::InternetStatusCallback()] Unhandled status: %lu\n"), dwInternetStatus); - } - - pRequest->pHttpFile->SetCompletionStatus(dwInternetStatus); -} - - -// ============================================================================ -/// CAsyncHttpFile::SetUrlHandle -/// @date 2009/04/18 -/// -/// @brief Sets the url handle. -/// @param[in] hOpenUrl Handle to be set. -// ============================================================================ -void CAsyncHttpFile::SetUrlHandle(HANDLE hOpenUrl) -{ - m_hOpenUrl = hOpenUrl; -} - -// ============================================================================ -/// CAsyncHttpFile::SetErrorCode -/// @date 2009/04/18 -/// -/// @brief Sets the error code. -/// @param[in] dwError Error code to be set. -// ============================================================================ -void CAsyncHttpFile::SetErrorCode(DWORD dwError) -{ - m_dwError = dwError; -} - -// ============================================================================ -/// CAsyncHttpFile::SetCompletionStatus -/// @date 2009/04/18 -/// -/// @brief Sets the completion status. -/// @param[in] dwCurrentState State to be set. -/// @return Result of the operation. -// ============================================================================ -HRESULT CAsyncHttpFile::SetCompletionStatus(DWORD dwCurrentState) -{ - if(!m_hFinishedEvent) - return E_FAIL; - - if(dwCurrentState == m_dwExpectedState || dwCurrentState == INTERNET_STATUS_CLOSING_CONNECTION) - return ::SetEvent(m_hFinishedEvent) ? S_OK : E_FAIL; - return S_FALSE; -} - -// ============================================================================ /// CUpdateChecker::CUpdateChecker /// @date 2009/04/18 /// /// @brief Constructs the update checker object. // ============================================================================ CUpdateChecker::CUpdateChecker() : - m_hThread(NULL), - m_hKillEvent(NULL), + m_hThread(nullptr), + m_hKillEvent(nullptr), m_eResult(eResult_Undefined), - m_bCheckForBeta(false) + m_eUpdateChannel(UpdateVersionInfo::eStable) { - m_hKillEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); + m_hKillEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); BOOST_ASSERT(m_hKillEvent); ::InitializeCriticalSection(&m_cs); } @@ -459,8 +53,17 @@ // ============================================================================ CUpdateChecker::~CUpdateChecker() { - Cleanup(); + try + { + Cleanup(); + } + catch (const std::exception&) + { + } + if(m_hKillEvent) + ::CloseHandle(m_hKillEvent); + ::DeleteCriticalSection(&m_cs); } @@ -473,28 +76,34 @@ /// @param[in] bCheckBeta States if we are interested in beta products. /// @return True if operation started, false otherwise. // ============================================================================ -bool CUpdateChecker::AsyncCheckForUpdates(const tchar_t* pszSite, bool bCheckBeta, bool bOnlyIfConnected) +bool CUpdateChecker::AsyncCheckForUpdates(const wchar_t* pszSite, const wchar_t* pszLanguage, UpdateVersionInfo::EVersionType eUpdateChannel, bool bOnlyIfConnected, bool bSendHeaders) { if(!pszSite) return false; + Cleanup(); + DWORD dwConnectionFlags = 0; if(bOnlyIfConnected && !InternetGetConnectedState(&dwConnectionFlags, 0)) return false; + ::EnterCriticalSection(&m_cs); + m_strSite = pszSite; m_eResult = eResult_Undefined; - m_bCheckForBeta = bCheckBeta; + m_eUpdateChannel = eUpdateChannel; + m_strLanguage = pszLanguage; + m_bSendHeaders = bSendHeaders; + ::LeaveCriticalSection(&m_cs); + ::ResetEvent(m_hKillEvent); - m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&CUpdateChecker::UpdateCheckThread, (void*)this, 0, NULL); + m_hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)&CUpdateChecker::UpdateCheckThread, (void*)this, 0, nullptr); if(!m_hThread) { - m_strSite.Empty(); - m_eResult = eResult_Undefined; - m_bCheckForBeta = false; + Cleanup(); return false; } @@ -513,23 +122,31 @@ { if(m_hKillEvent) ::SetEvent(m_hKillEvent); - WaitForSingleObject(m_hThread, 5000); - if(m_hKillEvent) - ::CloseHandle(m_hKillEvent); + DWORD dwResult = WaitForSingleObject(m_hThread, 5000); + if (dwResult == WAIT_TIMEOUT || dwResult == WAIT_FAILED) + throw std::exception("Failed to stop update checker thread."); + + m_hThread = nullptr; } + ::ResetEvent(m_hKillEvent); + m_httpFile.Close(); ::EnterCriticalSection(&m_cs); - m_hThread = NULL; - m_hKillEvent = NULL; + m_strSite.Empty(); - m_bCheckForBeta = false; + m_eUpdateChannel = UpdateVersionInfo::eStable; + m_strLanguage.Empty(); m_strLastError.Empty(); m_strNumericVersion.Empty(); m_strReadableVersion.Empty(); + m_strReleaseDate.Empty(); m_strDownloadAddress.Empty(); + m_strReleaseNotes.Empty(); m_eResult = CUpdateChecker::eResult_Undefined; + m_bSendHeaders = true; + ::LeaveCriticalSection(&m_cs); } @@ -543,31 +160,14 @@ // ============================================================================ void CUpdateChecker::SetResult(ECheckResult eCheckResult, DWORD dwError) { - CString strError; - + chcore::TString strError; if(eCheckResult == eResult_Error && dwError != 0) - { - PTSTR pszBuffer = strError.GetBufferSetLength(_MAX_PATH); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pszBuffer, _MAX_PATH, NULL); - strError.ReleaseBuffer(); + strError = chcore::TWin32ErrorFormatter::FormatWin32ErrorCodeWithFallback(dwError, _T("wininet.dll"), true); - if(strError.IsEmpty()) - { - pszBuffer = strError.GetBufferSetLength(_MAX_PATH); - FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(_T("wininet.dll")), dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pszBuffer, _MAX_PATH, NULL); - strError.ReleaseBuffer(); - } - - if(strError.IsEmpty()) - strError.Format(_T("0x%lx"), dwError); - } - - strError.TrimRight(_T("\r\n \t")); - ::EnterCriticalSection(&m_cs); m_eResult = eCheckResult; - m_strLastError = strError; + m_strLastError = strError.c_str(); ::LeaveCriticalSection(&m_cs); } @@ -595,27 +195,38 @@ /// @param[in] pszNumericVersion Numeric version number. /// @param[in] pszReadableVersion Human readable version number. // ============================================================================ -void CUpdateChecker::SetVersionsAndAddress(PCTSTR pszAddress, PCTSTR pszNumericVersion, PCTSTR pszReadableVersion) +void CUpdateChecker::SetVersionsAndAddress(PCTSTR pszAddress, PCTSTR pszNumericVersion, PCTSTR pszReadableVersion, PCTSTR pszReleaseDate, PCTSTR pszReleaseNotes) { ::EnterCriticalSection(&m_cs); m_strDownloadAddress = pszAddress; m_strNumericVersion = pszNumericVersion; m_strReadableVersion = pszReadableVersion; + m_strReleaseDate = pszReleaseDate; + m_strReleaseNotes = pszReleaseNotes; ::LeaveCriticalSection(&m_cs); } +void CUpdateChecker::SetSendHeaders(bool bSendHeaders) +{ + ::EnterCriticalSection(&m_cs); + m_bSendHeaders = bSendHeaders; + ::LeaveCriticalSection(&m_cs); +} + // ============================================================================ /// CUpdateChecker::GetSiteAddress /// @date 2009/04/18 /// /// @brief Retrieves the address of a site to check the updates at. /// @param[out] rstrAddress Receives the address. // ============================================================================ -void CUpdateChecker::GetSiteAddress(CString& rstrAddress) const +CString CUpdateChecker::GetSiteAddress() const { ::EnterCriticalSection(&m_cs); - rstrAddress = m_strSite; + CString strAddress = m_strSite; ::LeaveCriticalSection(&m_cs); + + return strAddress; } // ============================================================================ @@ -625,13 +236,13 @@ /// @brief Returns information, if update should check for beta versions. /// @return True if beta versions should be processed, false otherwise. // ============================================================================ -bool CUpdateChecker::CheckForBeta() +UpdateVersionInfo::EVersionType CUpdateChecker::GetUpdateChannel() { ::EnterCriticalSection(&m_cs); - bool bCheckForBeta = m_bCheckForBeta; + UpdateVersionInfo::EVersionType eUpdateChannel = m_eUpdateChannel; ::LeaveCriticalSection(&m_cs); - return bCheckForBeta; + return eUpdateChannel; } // ============================================================================ @@ -661,147 +272,141 @@ { CUpdateChecker* pUpdateChecker = (CUpdateChecker*)pParam; - // mark as started - pUpdateChecker->SetResult(eResult_Pending, 0); + try + { + // mark as started + pUpdateChecker->SetResult(eResult_Pending, 0); - // get the real address of file to download - CString strSite; - pUpdateChecker->GetSiteAddress(strSite); - strSite += _T("/chver.ini"); + CAsyncHttpFile::EWaitResult eWaitResult = CAsyncHttpFile::ePending; + size_t stFileSize = 0; + std::stringstream dataBuffer; - CAsyncHttpFile::EWaitResult eWaitResult = CAsyncHttpFile::ePending; - size_t stFileSize = 0; - byte_t* pbyBuffer = NULL; - icpf::circular_buffer circBuffer; + // open the connection and try to get to the file + std::wstring wstrUserAgent = pUpdateChecker->m_tUpdateHeaders.GetUserAgent((PCTSTR)pUpdateChecker->m_strLanguage, pUpdateChecker->m_eUpdateChannel); + std::wstring wstrHeaders; + if(pUpdateChecker->GetSendHeaders()) + wstrHeaders = pUpdateChecker->m_tUpdateHeaders.GetHeaders((PCTSTR)pUpdateChecker->m_strLanguage, pUpdateChecker->m_eUpdateChannel); - // open the connection and try to get to the file - HRESULT hResult = pUpdateChecker->m_httpFile.Open(strSite); - if(SUCCEEDED(hResult)) - { - eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); - switch(eWaitResult) + // get the real address of file to download + CString strSite = pUpdateChecker->GetSiteAddress(); + + HRESULT hResult = pUpdateChecker->m_httpFile.Open(strSite, wstrUserAgent.c_str(), wstrHeaders.c_str()); + if(SUCCEEDED(hResult)) { - case CAsyncHttpFile::eFinished: - break; - case CAsyncHttpFile::eKilled: - pUpdateChecker->SetResult(eResult_Killed, 0); - return 1; - case CAsyncHttpFile::eError: - pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); - return 1; - case CAsyncHttpFile::eTimeout: - case CAsyncHttpFile::ePending: - default: - pUpdateChecker->SetResult(eResult_Error, 0); - return 1; - } + eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); + switch(eWaitResult) + { + case CAsyncHttpFile::eFinished: + break; - // get the file size - hResult = pUpdateChecker->m_httpFile.GetFileSize(stFileSize); - } + case CAsyncHttpFile::eKilled: + pUpdateChecker->SetResult(eResult_Killed, 0); + pUpdateChecker->m_httpFile.Close(); + return 1; - if(SUCCEEDED(hResult)) - { - bool bIsClosed = false; - pbyBuffer = new byte_t[stFileSize]; - do + case CAsyncHttpFile::eError: + pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); + pUpdateChecker->m_httpFile.Close(); + return 1; + + case CAsyncHttpFile::eTimeout: + case CAsyncHttpFile::ePending: + default: + pUpdateChecker->SetResult(eResult_Error, 0); + pUpdateChecker->m_httpFile.Close(); + return 1; + } + + // get the file size + hResult = pUpdateChecker->m_httpFile.GetFileSize(stFileSize); + } + + if(SUCCEEDED(hResult)) { - hResult = pUpdateChecker->m_httpFile.RequestData(pbyBuffer, stFileSize); - if(SUCCEEDED(hResult)) + bool bIsClosed = false; + char* pbyBuffer = new char[ stFileSize ]; + do { - eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); - switch(eWaitResult) + hResult = pUpdateChecker->m_httpFile.RequestData(pbyBuffer, stFileSize); + if(SUCCEEDED(hResult)) { - case CAsyncHttpFile::eFinished: - break; - case CAsyncHttpFile::eKilled: - pUpdateChecker->SetResult(eResult_Killed, 0); - return 1; - break; - case CAsyncHttpFile::eError: - pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); - return 1; - case CAsyncHttpFile::eTimeout: - case CAsyncHttpFile::ePending: - default: - pUpdateChecker->SetResult(eResult_Error, 0); - return 1; - } - } + eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); + switch(eWaitResult) + { + case CAsyncHttpFile::eFinished: + break; + case CAsyncHttpFile::eKilled: + pUpdateChecker->SetResult(eResult_Killed, 0); + pUpdateChecker->m_httpFile.Close(); + return 1; - if(SUCCEEDED(hResult)) - hResult = pUpdateChecker->m_httpFile.GetRetrievedDataSize(stFileSize); + case CAsyncHttpFile::eError: + pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); + pUpdateChecker->m_httpFile.Close(); + return 1; - if(SUCCEEDED(hResult) && stFileSize) - circBuffer.push_data(pbyBuffer, stFileSize); + case CAsyncHttpFile::eTimeout: + case CAsyncHttpFile::ePending: + default: + pUpdateChecker->SetResult(eResult_Error, 0); + pUpdateChecker->m_httpFile.Close(); + return 1; + } + } - bIsClosed = pUpdateChecker->m_httpFile.IsClosed(); - } - while(stFileSize && !bIsClosed && SUCCEEDED(hResult)); + if(SUCCEEDED(hResult)) + hResult = pUpdateChecker->m_httpFile.GetRetrievedDataSize(stFileSize); - delete [] pbyBuffer; - } + if(SUCCEEDED(hResult) && stFileSize) + dataBuffer.write(pbyBuffer, stFileSize); - if(FAILED(hResult)) - { - pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); - return 1; - } + bIsClosed = pUpdateChecker->m_httpFile.IsClosed(); + } + while(stFileSize && !bIsClosed && SUCCEEDED(hResult)); - pUpdateChecker->m_httpFile.Close(); + delete[] pbyBuffer; + } - // convert text to unicode - icpf::config cfg(icpf::config::eIni); - const uint_t uiVersionNumeric = cfg.register_string(_t("Version/Numeric"), _t("")); - const uint_t uiVersionReadable = cfg.register_string(_t("Version/Human Readable"), _t("")); - const uint_t uiDownloadAddress = cfg.register_string(_t("Version/Download Address"), strSite); - const uint_t uiBetaVersionNumeric = cfg.register_string(_t("Version/Numeric Beta"), _t("")); - const uint_t uiBetaVersionReadable = cfg.register_string(_t("Version/Human Readable Beta"), _t("")); - const uint_t uiBetaDownloadAddress = cfg.register_string(_t("Version/Download Address Beta"), strSite); - try - { - cfg.read_from_buffer((TCHAR*)circBuffer.get_buffer(), (circBuffer.get_datasize() + 1) / 2); - } - catch(icpf::exception& e) - { - pUpdateChecker->SetResult(eResult_Error, 0); - pUpdateChecker->SetLastError(e.get_desc()); + if(FAILED(hResult)) + { + pUpdateChecker->SetResult(eResult_Error, pUpdateChecker->m_httpFile.GetErrorCode()); + pUpdateChecker->m_httpFile.Close(); + return 1; + } - return 0xffffffff; - } + pUpdateChecker->m_httpFile.Close(); - CString strVersionNumeric; - bool bCheckForBeta = pUpdateChecker->CheckForBeta(); - if(bCheckForBeta) - { - strVersionNumeric = cfg.get_string(uiBetaVersionNumeric); - pUpdateChecker->SetVersionsAndAddress(cfg.get_string(uiBetaDownloadAddress), strVersionNumeric, cfg.get_string(uiBetaVersionReadable)); - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// + UpdateVersionInfo::EVersionType eUpdateChannel = pUpdateChecker->GetUpdateChannel(); - if(!bCheckForBeta || strVersionNumeric.IsEmpty()) - { - strVersionNumeric = cfg.get_string(uiVersionNumeric); - pUpdateChecker->SetVersionsAndAddress(cfg.get_string(uiDownloadAddress), strVersionNumeric, cfg.get_string(uiVersionReadable)); + UpdateResponse response(dataBuffer); + UpdateVersionInfo vi; + bool bHasUpdates = response.GetVersions().FindUpdateInfo(eUpdateChannel, vi); + if(bHasUpdates) + { + pUpdateChecker->SetVersionsAndAddress(vi.GetDownloadLink().c_str(), vi.GetNumericVersion().c_str(), vi.GetReadableVersion().c_str(), + FormatDate(vi.GetDateRelease()).c_str(), vi.GetReleaseNotes().c_str()); + pUpdateChecker->SetResult(eResult_RemoteVersionNewer, 0); + } + else + pUpdateChecker->SetResult(eResult_VersionCurrent, 0); } - - // and compare to current version - ushort_t usVer[4]; - if(_stscanf(strVersionNumeric, _t("%hu.%hu.%hu.%hu"), &usVer[0], &usVer[1], &usVer[2], &usVer[3]) != 4) + catch(const std::exception&) { - TRACE(_T("Error parsing retrieved version number.")); pUpdateChecker->SetResult(eResult_Error, 0); - return 0xffffffff; } - ull_t ullCurrentVersion = ((ull_t)PRODUCT_VERSION1) << 48 | ((ull_t)PRODUCT_VERSION2) << 32 | ((ull_t)PRODUCT_VERSION3) << 16 | ((ull_t)PRODUCT_VERSION4); - ull_t ullSiteVersion = ((ull_t)usVer[0]) << 48 | ((ull_t)usVer[1]) << 32 | ((ull_t)usVer[2]) << 16 | ((ull_t)usVer[3]); + return 0; +} - if(ullCurrentVersion < ullSiteVersion) - pUpdateChecker->SetResult(eResult_RemoteVersionNewer, 0); - else if(ullCurrentVersion == ullSiteVersion) - pUpdateChecker->SetResult(eResult_VersionCurrent, 0); - else - pUpdateChecker->SetResult(eResult_RemoteVersionOlder, 0); +std::wstring CUpdateChecker::FormatDate(const boost::gregorian::date& date) +{ + using namespace boost::gregorian; - return 0; + std::wstringstream ss; + wdate_facet * fac = new wdate_facet(L"%Y-%m-%d"); + ss.imbue(std::locale(std::locale::classic(), fac)); + + ss << date; + return ss.str(); }