Index: src/ch/AsyncHttpFile.cpp =================================================================== diff -u -N --- src/ch/AsyncHttpFile.cpp (revision 0) +++ src/ch/AsyncHttpFile.cpp (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,428 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#include "stdafx.h" +#include "AsyncHttpFile.h" + +// timeout used with waiting for events (avoiding hangs) +#define FORCE_TIMEOUT 60000 + +using details::CONTEXT_REQUEST; + +// ============================================================================ +/// 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 wchar_t* pszPath, const wchar_t* pszUserAgent, const wchar_t* pszHeaders) +{ + 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(pszUserAgent, 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, pszHeaders, (DWORD)-1, 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; +} Index: src/ch/AsyncHttpFile.h =================================================================== diff -u -N --- src/ch/AsyncHttpFile.h (revision 0) +++ src/ch/AsyncHttpFile.h (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,100 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __ASYNCHTTPFILE_H__ +#define __ASYNCHTTPFILE_H__ + +class CAsyncHttpFile; + +namespace details +{ + struct CONTEXT_REQUEST + { + enum EOperation + { + eNone, + eInternetOpenUrl = 1, + eInternetReadFileEx = 2, + }; + + CAsyncHttpFile* pHttpFile; + EOperation eOperationType; + }; +} + +class CAsyncHttpFile +{ +public: + enum EWaitResult + { + eKilled, + eFinished, + eTimeout, + ePending, + eError + }; + +public: + CAsyncHttpFile(); + ~CAsyncHttpFile(); + + HRESULT Open(const wchar_t* pszPath, const wchar_t* pszUserAgent, const wchar_t* pszHeaders); + HRESULT GetFileSize(size_t& stSize); + + HRESULT RequestData(void* pBuffer, size_t stSize); + HRESULT GetRetrievedDataSize(size_t& stSize); + + HRESULT Close(); + + EWaitResult GetResult(); + DWORD GetErrorCode() + { + return m_dwError; + } + + EWaitResult WaitForResult(HANDLE hKillEvent); + + bool IsClosed() const + { + return m_hOpenUrl == NULL; + } + +protected: + static void CALLBACK InternetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength); + + void SetUrlHandle(HANDLE hOpenUrl); + void SetErrorCode(DWORD dwError); + + /// Sets the completion event + HRESULT SetCompletionStatus(DWORD dwCurrentState); + +protected: + HINTERNET m_hInternet; + HINTERNET m_hOpenUrl; + + DWORD m_dwExpectedState; ///< State we are expecting + HANDLE m_hFinishedEvent; + + INTERNET_BUFFERS m_internetBuffers; + details::CONTEXT_REQUEST m_tOpenRequest; + details::CONTEXT_REQUEST m_tReadRequest; + + DWORD m_dwError; +}; + +#endif Index: src/ch/CfgProperties.h =================================================================== diff -u -N -r73d92717b7ba780c7aea1489a5eaa87404afa408 -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/CfgProperties.h (.../CfgProperties.h) (revision 73d92717b7ba780c7aea1489a5eaa87404afa408) +++ src/ch/CfgProperties.h (.../CfgProperties.h) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -22,6 +22,7 @@ #pragma once #include "../libchcore/TTaskConfiguration.h" +#include "UpdateVersionInfo.h" namespace chcore { class TConfig; } @@ -32,7 +33,7 @@ PP_PMONITORSCANINTERVAL, PP_PRELOADAFTERRESTART, PP_PCHECK_FOR_UPDATES_FREQUENCY, - PP_PUPDATE_CHECK_FOR_BETA, + PP_PUPDATECHANNEL, PP_PSHUTDOWNAFTREFINISHED, PP_PTIMEBEFORESHUTDOWN, PP_PFORCESHUTDOWN, @@ -178,7 +179,7 @@ PROPERTY(PP_PRELOADAFTERRESTART, bool, _T("CHConfig.General.Program.RunWithSystem"), false); PROPERTY_MINMAX(PP_PCHECK_FOR_UPDATES_FREQUENCY, unsigned int, _T("CHConfig.General.Program.Updates.Frequency"), eFreq_Weekly, eFreq_Never, eFreq_Max - 1); -PROPERTY(PP_PUPDATE_CHECK_FOR_BETA, bool, _T("CHConfig.General.Program.Updates.CheckForBetaVersions"), true); +PROPERTY_MINMAX(PP_PUPDATECHANNEL, int, _T("CHConfig.General.Program.Updates.UpdateChannel"), UpdateVersionInfo::eReleaseCandidate, UpdateVersionInfo::eStable, UpdateVersionInfo::eMax - 1); PROPERTY(PP_PPROCESSPRIORITYCLASS, int, _T("CHConfig.General.Program.ProcessPriority"), NORMAL_PRIORITY_CLASS); PROPERTY(PP_PLANGUAGE, CString, _T("CHConfig.General.Program.Language"), _T("\\Langs\\English.lng")); Index: src/ch/OptionsDlg.cpp =================================================================== diff -u -N -rcdc76e1a95383dff63a5254aeb8d37035028512c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/OptionsDlg.cpp (.../OptionsDlg.cpp) (revision cdc76e1a95383dff63a5254aeb8d37035028512c) +++ src/ch/OptionsDlg.cpp (.../OptionsDlg.cpp) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -226,7 +226,7 @@ PROP_UINT(IDS_CLIPBOARDINTERVAL_STRING, GetPropValue(GetConfig())); PROP_BOOL(IDS_AUTORUNPROGRAM_STRING, GetPropValue(GetConfig())); PROP_COMBO(IDS_CFG_CHECK_FOR_UPDATES_FREQUENCY, IDS_UPDATE_FREQUENCIES, GetPropValue(GetConfig())); - PROP_BOOL(IDS_CFG_UPDATE_CHECK_FOR_BETA, GetPropValue(GetConfig())); + PROP_COMBO(IDS_CFG_UPDATECHANNEL, IDS_CFGUPDATECHANNELITEMS_STRING, GetPropValue(GetConfig())); PROP_BOOL(IDS_AUTOSHUTDOWN_STRING, GetPropValue(GetConfig())); PROP_UINT(IDS_SHUTDOWNTIME_STRING, GetPropValue(GetConfig())); PROP_COMBO(IDS_FORCESHUTDOWN_STRING, IDS_FORCESHUTDOWNVALUES_STRING, GetPropValue(GetConfig()) ? 1 : 0); @@ -340,7 +340,7 @@ SetPropValue(rConfig, GetUintProp(iPosition++)); SetPropValue(rConfig, GetBoolProp(iPosition++)); SetPropValue(rConfig, GetIndexProp(iPosition++)); - SetPropValue(rConfig, GetBoolProp(iPosition++)); + SetPropValue(rConfig, GetBoolProp(iPosition++)); SetPropValue(rConfig, GetBoolProp(iPosition++)); SetPropValue(rConfig, GetUintProp(iPosition++)); SetPropValue(rConfig, GetBoolProp(iPosition++)); Index: src/ch/UpdateChecker.cpp =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/UpdateChecker.cpp (.../UpdateChecker.cpp) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/ch/UpdateChecker.cpp (.../UpdateChecker.cpp) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -22,422 +22,13 @@ // ============================================================================ #include "stdafx.h" #include "UpdateChecker.h" +#include "UpdateResponse.h" #include -#include -#include "../common/version.h" -#include "../libicpf/cfg.h" -#include "../libicpf/exception.h" -#include "../libicpf/circ_buffer.h" #include "../libchcore/TWin32ErrorFormatter.h" -#include "WindowsVersion.h" -#include +#include "../common/version.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, const wchar_t* pszUserAgent) -{ - 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(pszUserAgent, 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 /// @@ -447,7 +38,7 @@ m_hThread(NULL), m_hKillEvent(NULL), m_eResult(eResult_Undefined), - m_bCheckForBeta(false) + m_eUpdateChannel(UpdateVersionInfo::eStable) { m_hKillEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); BOOST_ASSERT(m_hKillEvent); @@ -476,7 +67,7 @@ /// @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) { if(!pszSite) return false; @@ -488,16 +79,18 @@ m_strSite = pszSite; m_eResult = eResult_Undefined; - m_bCheckForBeta = bCheckBeta; + m_eUpdateChannel = eUpdateChannel; + m_strLanguage = pszLanguage; ::ResetEvent(m_hKillEvent); m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&CUpdateChecker::UpdateCheckThread, (void*)this, 0, NULL); if(!m_hThread) { + m_strLanguage.Empty(); m_strSite.Empty(); m_eResult = eResult_Undefined; - m_bCheckForBeta = false; + m_eUpdateChannel = UpdateVersionInfo::eStable; return false; } @@ -527,10 +120,12 @@ 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_eResult = CUpdateChecker::eResult_Undefined; ::LeaveCriticalSection(&m_cs); @@ -581,12 +176,14 @@ /// @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); } @@ -611,29 +208,15 @@ /// @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; } -std::wstring CUpdateChecker::GetUserAgent() -{ - std::wstring wstrUserAgent(PRODUCT_FULL_VERSION_T); - wstrUserAgent += L" (" + - boost::lexical_cast(PRODUCT_VERSION1) + L"." + - boost::lexical_cast(PRODUCT_VERSION2) + L"." + - boost::lexical_cast(PRODUCT_VERSION3) + L"." + - boost::lexical_cast(PRODUCT_VERSION4) + L")"; - - wstrUserAgent += L" (" + WindowsVersion::GetWindowsVersion() + L")"; - - return wstrUserAgent; -} - // ============================================================================ /// CUpdateChecker::GetResult /// @date 2009/04/18 @@ -667,19 +250,16 @@ // get the real address of file to download CString strSite; pUpdateChecker->GetSiteAddress(strSite); - strSite += _T("/chver.ini"); + strSite += _T("/chupdate.php"); CAsyncHttpFile::EWaitResult eWaitResult = CAsyncHttpFile::ePending; size_t stFileSize = 0; - byte_t* pbyBuffer = NULL; + std::stringstream dataBuffer; - const size_t stReserveBuffer = 1024; - std::vector vBuffer; - vBuffer.reserve(stReserveBuffer); - // open the connection and try to get to the file - std::wstring wstrUserAgent = GetUserAgent(); - HRESULT hResult = pUpdateChecker->m_httpFile.Open(strSite, wstrUserAgent.c_str()); + std::wstring wstrUserAgent = pUpdateChecker->m_tUpdateHeaders.GetUserAgent(); + std::wstring wstrHeaders = pUpdateChecker->m_tUpdateHeaders.GetHeaders((PCTSTR)pUpdateChecker->m_strLanguage); + HRESULT hResult = pUpdateChecker->m_httpFile.Open(strSite, wstrUserAgent.c_str(), wstrHeaders.c_str()); if(SUCCEEDED(hResult)) { eWaitResult = pUpdateChecker->m_httpFile.WaitForResult(pUpdateChecker->m_hKillEvent); @@ -707,7 +287,7 @@ if(SUCCEEDED(hResult)) { bool bIsClosed = false; - pbyBuffer = new byte_t[stFileSize]; + char* pbyBuffer = new char[stFileSize]; do { hResult = pUpdateChecker->m_httpFile.RequestData(pbyBuffer, stFileSize); @@ -737,7 +317,7 @@ hResult = pUpdateChecker->m_httpFile.GetRetrievedDataSize(stFileSize); if(SUCCEEDED(hResult) && stFileSize) - vBuffer.insert(vBuffer.end(), pbyBuffer, pbyBuffer + stFileSize); + dataBuffer.write(pbyBuffer, stFileSize); bIsClosed = pUpdateChecker->m_httpFile.IsClosed(); } @@ -754,58 +334,32 @@ pUpdateChecker->m_httpFile.Close(); - // 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((wchar_t*)&vBuffer[0], vBuffer.size() / sizeof(wchar_t)); - } - catch(icpf::exception& e) - { - pUpdateChecker->SetResult(eResult_Error, 0); - pUpdateChecker->SetLastError(e.get_desc()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// + UpdateVersionInfo::EVersionType eUpdateChannel = pUpdateChecker->GetUpdateChannel(); - return 0xffffffff; - } - - CString strVersionNumeric; - bool bCheckForBeta = pUpdateChecker->CheckForBeta(); - if(bCheckForBeta) + UpdateResponse response(dataBuffer); + UpdateVersionInfo vi; + bool bHasUpdates = response.GetVersions().FindUpdateInfo(eUpdateChannel ? UpdateVersionInfo::eBeta : UpdateVersionInfo::eStable, vi); + if(bHasUpdates) { - strVersionNumeric = cfg.get_string(uiBetaVersionNumeric); - pUpdateChecker->SetVersionsAndAddress(cfg.get_string(uiBetaDownloadAddress), strVersionNumeric, cfg.get_string(uiBetaVersionReadable)); + 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); - if(!bCheckForBeta || strVersionNumeric.IsEmpty()) - { - strVersionNumeric = cfg.get_string(uiVersionNumeric); - pUpdateChecker->SetVersionsAndAddress(cfg.get_string(uiDownloadAddress), strVersionNumeric, cfg.get_string(uiVersionReadable)); - } + return 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) - { - TRACE(_T("Error parsing retrieved version number.")); - pUpdateChecker->SetResult(eResult_Error, 0); - return 0xffffffff; - } +std::wstring CUpdateChecker::FormatDate(const boost::gregorian::date& date) +{ + using namespace boost::gregorian; - 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]); + std::wstringstream ss; + wdate_facet * fac = new wdate_facet(L"%Y-%m-%d"); + ss.imbue(std::locale(std::locale::classic(), fac)); - if(ullCurrentVersion < ullSiteVersion) - pUpdateChecker->SetResult(eResult_RemoteVersionNewer, 0); - else if(ullCurrentVersion == ullSiteVersion) - pUpdateChecker->SetResult(eResult_VersionCurrent, 0); - else - pUpdateChecker->SetResult(eResult_RemoteVersionOlder, 0); - - return 0; + ss << date; + return ss.str(); } Index: src/ch/UpdateChecker.h =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/UpdateChecker.h (.../UpdateChecker.h) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/ch/UpdateChecker.h (.../UpdateChecker.h) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -23,74 +23,11 @@ #ifndef __UPDATECHECKER_H__ #define __UPDATECHECKER_H__ -class CAsyncHttpFile; +#include "WindowsVersion.h" +#include "AsyncHttpFile.h" +#include "UpdateHeaders.h" +#include "UpdateVersionInfo.h" -struct CONTEXT_REQUEST -{ - CAsyncHttpFile* pHttpFile; - enum EOperation - { - eNone, - eInternetOpenUrl = 1, - eInternetReadFileEx = 2, - } eOperationType; -}; - -class CAsyncHttpFile -{ -public: - enum EWaitResult - { - eKilled, - eFinished, - eTimeout, - ePending, - eError - }; - -public: - CAsyncHttpFile(); - ~CAsyncHttpFile(); - - HRESULT Open(const wchar_t* pszPath, const wchar_t* pszUserAgent); - HRESULT GetFileSize(size_t& stSize); - - HRESULT RequestData(void* pBuffer, size_t stSize); - HRESULT GetRetrievedDataSize(size_t& stSize); - - HRESULT Close(); - - EWaitResult GetResult(); - DWORD GetErrorCode() { return m_dwError; } - - EWaitResult WaitForResult(HANDLE hKillEvent); - - bool IsClosed() const { return m_hOpenUrl == NULL; } - -protected: - static void CALLBACK InternetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength); - - void SetUrlHandle(HANDLE hOpenUrl); - void SetErrorCode(DWORD dwError); - - /// Sets the completion event - HRESULT SetCompletionStatus(DWORD dwCurrentState); - -protected: - HINTERNET m_hInternet; - HINTERNET m_hOpenUrl; - - DWORD m_dwExpectedState; ///< State we are expecting - HANDLE m_hFinishedEvent; - - INTERNET_BUFFERS m_internetBuffers; - CONTEXT_REQUEST m_tOpenRequest; - CONTEXT_REQUEST m_tReadRequest; - - - DWORD m_dwError; -}; - class CUpdateChecker : protected CInternetSession { public: @@ -100,7 +37,6 @@ eResult_Pending, eResult_Killed, eResult_Error, - eResult_RemoteVersionOlder, eResult_VersionCurrent, eResult_RemoteVersionNewer }; @@ -112,7 +48,7 @@ ~CUpdateChecker(); /// Starts the 'check for updates' thread - bool AsyncCheckForUpdates(const tchar_t* pszSite, bool bCheckBeta, bool bOnlyIfConnected); + bool AsyncCheckForUpdates(const wchar_t* pszSite, const wchar_t* pszLanguage, UpdateVersionInfo::EVersionType bCheckBeta, bool bOnlyIfConnected); /// Stops checking and cleanups the object void Cleanup(); @@ -121,10 +57,12 @@ ECheckResult GetResult() const; // methods for retrieving state - const tchar_t* GetNumericVersion() const { return (const tchar_t*)m_strNumericVersion; } - const tchar_t* GetReadableVersion() const { return (const tchar_t*)m_strReadableVersion; } - const tchar_t* GetLastError() const { return (const tchar_t*)m_strLastError; } - const tchar_t* GetDownloadAddress() const { return m_strDownloadAddress; } + const wchar_t* GetNumericVersion() const { return (const wchar_t*)m_strNumericVersion; } + const wchar_t* GetReadableVersion() const { return (const wchar_t*)m_strReadableVersion; } + const wchar_t* GetLastError() const { return (const wchar_t*)m_strLastError; } + const wchar_t* GetDownloadAddress() const { return m_strDownloadAddress; } + const wchar_t* GetReleaseDate() const { return m_strReleaseDate; } + const wchar_t* GetReleaseNotes() const { return m_strReleaseNotes; } protected: /// Thread function (handles most of the internet connection operation) @@ -135,27 +73,31 @@ /// Sets the last error void SetLastError(PCTSTR pszError); /// Sets the versions and download address - void SetVersionsAndAddress(PCTSTR pszAddress, PCTSTR pszNumericVersion, PCTSTR pszReadableVersion); + void SetVersionsAndAddress(PCTSTR pszAddress, PCTSTR pszNumericVersion, PCTSTR pszReadableVersion, PCTSTR pszReleaseDate, PCTSTR pszReleaseNotes); /// Retrieves the site address void GetSiteAddress(CString& rstrAddress) const; /// Returns information if we're interested in beta versions - bool CheckForBeta(); + UpdateVersionInfo::EVersionType GetUpdateChannel(); + static std::wstring FormatDate(const boost::gregorian::date& date); - // user agent - static std::wstring GetUserAgent(); - protected: CString m_strSite; - bool m_bCheckForBeta; + UpdateVersionInfo::EVersionType m_eUpdateChannel; + CString m_strLanguage; CString m_strLastError; CString m_strNumericVersion; CString m_strReadableVersion; CString m_strDownloadAddress; + CString m_strReleaseDate; + CString m_strReleaseNotes; ECheckResult m_eResult; CAsyncHttpFile m_httpFile; + UpdateHeaders m_tUpdateHeaders; + + HANDLE m_hThread; HANDLE m_hKillEvent; mutable CRITICAL_SECTION m_cs; Index: src/ch/UpdateHeaders.cpp =================================================================== diff -u -N --- src/ch/UpdateHeaders.cpp (revision 0) +++ src/ch/UpdateHeaders.cpp (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,80 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#include "stdafx.h" +#include "UpdateHeaders.h" +#include "WindowsVersion.h" +#include +#include +#include "..\common\version.h" + +UpdateHeaders::UpdateHeaders() +{ +} + +std::wstring UpdateHeaders::GetUserAgent() +{ + std::wstring wstrUserAgent(PRODUCT_FULL_VERSION_T); + wstrUserAgent += L" (" + + boost::lexical_cast(PRODUCT_VERSION1) + L"." + + boost::lexical_cast(PRODUCT_VERSION2) + L"." + + boost::lexical_cast(PRODUCT_VERSION3) + L"." + + boost::lexical_cast(PRODUCT_VERSION4) + L")"; + + wstrUserAgent += L" (" + m_tWindowsVersion.GetWindowsVersion() + L")"; + + return wstrUserAgent; +} + +std::wstring UpdateHeaders::GetHeaders(const std::wstring& wstrLanguagePath) +{ + std::wstring wstrLanguage; + size_t stPos = wstrLanguagePath.rfind(L'\\'); + if(stPos != std::wstring::npos) + wstrLanguage = wstrLanguagePath.substr(stPos + 1); + else + wstrLanguage = L"unknown"; + + std::wstring wstrHeaders; + + // copy handler version + wstrHeaders = L"CopyHandler-Version: " + + boost::lexical_cast(PRODUCT_VERSION1) + L"." + + boost::lexical_cast(PRODUCT_VERSION2) + L"." + + boost::lexical_cast(PRODUCT_VERSION3) + L"." + + boost::lexical_cast(PRODUCT_VERSION4) + L"\r\n"; + + // system version + wstrHeaders += L"CopyHandler-OSVersionNumeric: " + m_tWindowsVersion.GetWindowsVersionNumeric() + L"\r\n"; + wstrHeaders += L"CopyHandler-OSReadableVersion: " + m_tWindowsVersion.GetWindowsVersionLongName() + L"\r\n"; + wstrHeaders += L"CopyHandler-OSInstallType: " + m_tWindowsVersion.GetWindowsInstallType() + L"\r\n"; + + // cpu/os arch + wstrHeaders += L"CopyHandler-OSArch: " + m_tWindowsVersion.GetCpuArch() + L"\r\n"; + + // language + wstrHeaders += L"CopyHandler-Language: " + wstrLanguage + L"\r\n"; + + // #todo update channel + wstrHeaders += L"CopyHandler-UpdateChannel: beta\r\n"; + + // finalize + wstrHeaders += L"\r\n\r\n"; + + return wstrHeaders; +} Index: src/ch/UpdateHeaders.h =================================================================== diff -u -N --- src/ch/UpdateHeaders.h (revision 0) +++ src/ch/UpdateHeaders.h (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,36 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __UPDATEHEADERS_H__ +#define __UPDATEHEADERS_H__ + +#include "WindowsVersion.h" + +class UpdateHeaders +{ +public: + UpdateHeaders(); + + std::wstring GetUserAgent(); + std::wstring GetHeaders(const std::wstring& wstrLanguagePath); + +private: + WindowsVersion m_tWindowsVersion; +}; + +#endif Index: src/ch/UpdateMultipleVersionInfo.cpp =================================================================== diff -u -N --- src/ch/UpdateMultipleVersionInfo.cpp (revision 0) +++ src/ch/UpdateMultipleVersionInfo.cpp (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,54 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#include "stdafx.h" +#include "UpdateMultipleVersionInfo.h" +#include "../Common/version.h" + +UpdateMultipleVersionInfo::UpdateMultipleVersionInfo() +{ +} + +void UpdateMultipleVersionInfo::Add(UpdateVersionInfo::EVersionType eType, UpdateVersionInfo vi) +{ + auto iterFind = m_mapVersions.find(eType); + if(iterFind != m_mapVersions.end()) + iterFind->second.Merge(vi); + else + m_mapVersions.emplace(eType, std::move(vi)); +} + +bool UpdateMultipleVersionInfo::FindUpdateInfo(UpdateVersionInfo::EVersionType eUpdateChannel, UpdateVersionInfo& rOutVersionInfo) const +{ + unsigned long long ullFoundVersion = 0; + const unsigned long long ullCurrentProgramVersion = PRODUCT_FULL_NUMERIC_VERSION; + + for(const std::pair& pairInfo : m_mapVersions) + { + // ignore channels not fitting our settings + if(eUpdateChannel >= pairInfo.first && + pairInfo.second.GetFullNumericVersion() > ullCurrentProgramVersion && + pairInfo.second.GetFullNumericVersion() > ullFoundVersion) + { + rOutVersionInfo = pairInfo.second; + ullFoundVersion = pairInfo.second.GetFullNumericVersion(); + } + } + + return ullFoundVersion > 0; +} Index: src/ch/UpdateMultipleVersionInfo.h =================================================================== diff -u -N --- src/ch/UpdateMultipleVersionInfo.h (revision 0) +++ src/ch/UpdateMultipleVersionInfo.h (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,36 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __UPDATEMULTIPLEVERSIONINFO_H__ +#define __UPDATEMULTIPLEVERSIONINFO_H__ + +#include "UpdateVersionInfo.h" + +class UpdateMultipleVersionInfo +{ +public: + UpdateMultipleVersionInfo(); + void Add(UpdateVersionInfo::EVersionType eType, UpdateVersionInfo vi); + + bool FindUpdateInfo(UpdateVersionInfo::EVersionType eUpdateChannel, UpdateVersionInfo& rOutVersionInfo) const; + +private: + std::map m_mapVersions; +}; + +#endif Index: src/ch/UpdateResponse.cpp =================================================================== diff -u -N --- src/ch/UpdateResponse.cpp (revision 0) +++ src/ch/UpdateResponse.cpp (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,99 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#include "stdafx.h" +#include "UpdateResponse.h" +#include +#include +#include +#include +#include +#include +#include +#include + +UpdateResponse::UpdateResponse(std::stringstream& tDataStream) +{ + std::wstring_convert, wchar_t> conversion; + std::wstringstream wssData(conversion.from_bytes(tDataStream.str())); + + using namespace boost::property_tree; + wiptree pt; + read_xml(wssData, pt); + + // traverse pt + std::wstring wstrVersion; + std::wstring wstrReleaseDate; + std::wstring wstrReleaseNotes; + + for(const wiptree::value_type& node : pt.get_child(L"UpdateInfo")) + { + try + { + UpdateVersionInfo::EVersionType eType = ParseVersionName(node.first); + UpdateVersionInfo vi = ParseVersionInfo(node.second); + m_tVersions.Add(eType, std::move(vi)); + } + catch(const std::exception&) // ignore exceptions from version parsing code + { + } + } +} + +UpdateMultipleVersionInfo& UpdateResponse::GetVersions() +{ + return m_tVersions; +} + +UpdateVersionInfo::EVersionType UpdateResponse::ParseVersionName(const std::wstring& strVersionName) +{ + if(boost::iequals(strVersionName, L"Stable")) + return UpdateVersionInfo::eStable; + if(boost::iequals(strVersionName, L"RC")) + return UpdateVersionInfo::eReleaseCandidate; + if(boost::iequals(strVersionName, L"Beta")) + return UpdateVersionInfo::eBeta; + if(boost::iequals(strVersionName, L"Alpha")) + return UpdateVersionInfo::eAlpha; + + throw std::runtime_error("Unknown version received"); +} + +UpdateVersionInfo UpdateResponse::ParseVersionInfo(const boost::property_tree::wiptree& node) +{ + return UpdateVersionInfo(node.get(L"NumericVersion"), + node.get(L"ReadableVersion"), + ConvertDate(node.get(L"ReleaseDateUtc")), + node.get(L"DownloadLink"), + node.get(L"ReleaseNotes")); +} + +boost::gregorian::date UpdateResponse::ConvertDate(const std::wstring& wstrReleaseDate) +{ + using namespace boost::gregorian; + + std::wstringstream ss; + wdate_input_facet * fac = new wdate_input_facet(L"%Y-%m-%d"); + ss.imbue(std::locale(std::locale::classic(), fac)); + + boost::gregorian::date dtRelease; + ss << wstrReleaseDate; + ss >> dtRelease; + + return dtRelease; +} Index: src/ch/UpdateResponse.h =================================================================== diff -u -N --- src/ch/UpdateResponse.h (revision 0) +++ src/ch/UpdateResponse.h (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,42 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __UPDATERESPONSE_H__ +#define __UPDATERESPONSE_H__ + +#include "UpdateVersionInfo.h" +#include "UpdateMultipleVersionInfo.h" + +class UpdateResponse +{ +public: + UpdateResponse(std::stringstream& tDataStream); + + UpdateMultipleVersionInfo& GetVersions(); + +private: + UpdateVersionInfo::EVersionType ParseVersionName(const std::wstring& strVersionName); + UpdateVersionInfo ParseVersionInfo(const boost::property_tree::wiptree& node); + + boost::gregorian::date ConvertDate(const std::wstring& wstrReleaseDate); + +private: + UpdateMultipleVersionInfo m_tVersions; +}; + +#endif Index: src/ch/UpdateVersionInfo.cpp =================================================================== diff -u -N --- src/ch/UpdateVersionInfo.cpp (revision 0) +++ src/ch/UpdateVersionInfo.cpp (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,117 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#include "stdafx.h" +#include "UpdateVersionInfo.h" +#include +#include +#include + +UpdateVersionInfo::UpdateVersionInfo(std::wstring strNumericVersion, std::wstring strReadableVersion, boost::gregorian::date dateRelease, std::wstring strDownloadLink, std::wstring strReleaseNotes) : + m_strNumericVersion(strNumericVersion), + m_strReadableVersion(strReadableVersion), + m_dateRelease(dateRelease), + m_strDownloadLink(strDownloadLink), + m_strReleaseNotes(strReleaseNotes), + m_ullNumericVersion(ParseNumericVersion(strNumericVersion)) +{ +} + +UpdateVersionInfo::UpdateVersionInfo() +{ + +} + +void UpdateVersionInfo::Merge(UpdateVersionInfo vi) +{ + if(m_ullNumericVersion < vi.m_ullNumericVersion) + *this = std::move(vi); +} + +unsigned long long UpdateVersionInfo::GetFullNumericVersion() const +{ + return m_ullNumericVersion; +} + +std::wstring UpdateVersionInfo::GetNumericVersion() const +{ + return m_strNumericVersion; +} + +void UpdateVersionInfo::SetNumericVersion(std::wstring val) +{ + m_strNumericVersion = val; + m_ullNumericVersion = ParseNumericVersion(m_strNumericVersion); +} + +std::wstring UpdateVersionInfo::GetReadableVersion() const +{ + return m_strReadableVersion; +} + +void UpdateVersionInfo::SetReadableVersion(std::wstring val) +{ + m_strReadableVersion = val; +} + +boost::gregorian::date UpdateVersionInfo::GetDateRelease() const +{ + return m_dateRelease; +} + +void UpdateVersionInfo::SetDateRelease(boost::gregorian::date val) +{ + m_dateRelease = val; +} + +std::wstring UpdateVersionInfo::GetDownloadLink() const +{ + return m_strDownloadLink; +} + +void UpdateVersionInfo::SetDownloadLink(std::wstring val) +{ + m_strDownloadLink = val; +} + +std::wstring UpdateVersionInfo::GetReleaseNotes() const +{ + return m_strReleaseNotes; +} + +void UpdateVersionInfo::SetReleaseNotes(std::wstring val) +{ + m_strReleaseNotes = val; +} + +unsigned long long UpdateVersionInfo::ParseNumericVersion(const std::wstring& wstrNumericVersion) +{ + std::vector vParts; + boost::split(vParts, wstrNumericVersion, boost::is_any_of("."), boost::algorithm::token_compress_on); + + if(vParts.size() != 4) + throw std::runtime_error("Wrong version number received"); + + unsigned long long ullVersion = + (unsigned long long)boost::lexical_cast(vParts[ 0 ]) << 48 | + (unsigned long long)boost::lexical_cast(vParts[ 1 ]) << 32 | + (unsigned long long)boost::lexical_cast(vParts[ 2 ]) << 16 | + (unsigned long long)boost::lexical_cast(vParts[ 3 ]); + + return ullVersion; +} Index: src/ch/UpdateVersionInfo.h =================================================================== diff -u -N --- src/ch/UpdateVersionInfo.h (revision 0) +++ src/ch/UpdateVersionInfo.h (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -0,0 +1,74 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// 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 Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __UPDATEVERSIONINFO_H__ +#define __UPDATEVERSIONINFO_H__ + +#include +#include + +class UpdateVersionInfo +{ +public: + enum EVersionType + { + eStable, + eReleaseCandidate, + eBeta, + eAlpha, + + eMax + }; + +public: + UpdateVersionInfo(); + UpdateVersionInfo(std::wstring strNumericVersion, std::wstring strReadableVersion, boost::gregorian::date dateRelease, std::wstring strDownloadLink, std::wstring strReleaseNotes); + + void Merge(UpdateVersionInfo vi); + + unsigned long long GetFullNumericVersion() const; + std::wstring GetNumericVersion() const; + void SetNumericVersion(std::wstring val); + + std::wstring GetReadableVersion() const; + void SetReadableVersion(std::wstring val); + + boost::gregorian::date GetDateRelease() const; + void SetDateRelease(boost::gregorian::date val); + + std::wstring GetDownloadLink() const; + void SetDownloadLink(std::wstring val); + + std::wstring GetReleaseNotes() const; + void SetReleaseNotes(std::wstring val); + +private: + static unsigned long long ParseNumericVersion(const std::wstring& wstrNumericVersion); + +private: + std::wstring m_strNumericVersion; + unsigned long long m_ullNumericVersion = 0; + + std::wstring m_strReadableVersion; + boost::gregorian::date m_dateRelease; + + std::wstring m_strDownloadLink; + std::wstring m_strReleaseNotes; +}; + +#endif Index: src/ch/UpdaterDlg.cpp =================================================================== diff -u -N -r7972b0944e0a947144fbdb93262f7d73ac528dc7 -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision 7972b0944e0a947144fbdb93262f7d73ac528dc7) +++ src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -6,6 +6,7 @@ #include "UpdaterDlg.h" #include "UpdateChecker.h" #include "../common/version.h" +#include "StaticEx.h" #define UPDATER_TIMER 639 @@ -24,6 +25,7 @@ m_eLastState(CUpdateChecker::eResult_Undefined), m_bBackgroundMode(bBackgroundMode) { + RegisterStaticExControl(AfxGetInstanceHandle()); } CUpdaterDlg::~CUpdaterDlg() @@ -34,16 +36,19 @@ void CUpdaterDlg::DoDataExchange(CDataExchange* pDX) { ictranslate::CLanguageDialog::DoDataExchange(pDX); - DDX_Control(pDX, IDC_INFO_STATIC, m_ctlText); + DDX_Control(pDX, IDC_ICON_STATIC, m_ctlImage); + DDX_Control(pDX, IDC_MAINUPDATEINFO_CUSTOM, m_ctlMainText); + DDX_Control(pDX, IDC_CHANGELOG_RICHEDIT, m_ctlRichEdit); } BOOL CUpdaterDlg::OnInitDialog() { ictranslate::CLanguageDialog::OnInitDialog(); +/* ictranslate::CFormat fmt(GetResManager().LoadString(IDS_UPDATER_WAITING_STRING)); fmt.SetParam(_t("%site"), _T(PRODUCT_SITE)); - m_ctlText.SetWindowText(fmt); + m_ctlText.SetWindowText(fmt);*/ // disable button initially CWnd* pWnd = GetDlgItem(IDC_OPEN_WEBPAGE_BUTTON); @@ -54,7 +59,7 @@ ShowWindow(SW_SHOW); // start the updater - m_ucChecker.AsyncCheckForUpdates(_T(PRODUCT_SITE), GetPropValue(GetConfig()), m_bBackgroundMode); + m_ucChecker.AsyncCheckForUpdates(_T(PRODUCT_SITE), GetPropValue(GetConfig()), (UpdateVersionInfo::EVersionType)GetPropValue(GetConfig()), m_bBackgroundMode); // start a timer to display progress SetTimer(UPDATER_TIMER, 10, NULL); @@ -102,41 +107,52 @@ case CUpdateChecker::eResult_Undefined: TRACE(_T("CUpdateChecker::eResult_Undefined\n")); eBkMode = eRes_Exit; + UpdateIcon(eIcon_Info); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_CHECKINGFORUPDATES)); strFmt = rResManager.LoadString(IDS_UPDATER_WAITING_STRING); break; + case CUpdateChecker::eResult_Pending: TRACE(_T("CUpdateChecker::eResult_Pending\n")); + UpdateIcon(eIcon_Info); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_CHECKINGFORUPDATES)); strFmt = rResManager.LoadString(IDS_UPDATER_WAITING_STRING); break; + case CUpdateChecker::eResult_Killed: TRACE(_T("CUpdateChecker::eResult_Killed\n")); eBkMode = eRes_Exit; - strFmt = rResManager.LoadString(IDS_UPDATER_ERROR_STRING); + UpdateIcon(eIcon_Error); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_ERROR_STRING)); + strFmt = rResManager.LoadString(IDS_UPDATER_KILLEDERROR); break; + case CUpdateChecker::eResult_Error: TRACE(_T("CUpdateChecker::eResult_Error\n")); eBkMode = eRes_Exit; - strFmt = rResManager.LoadString(IDS_UPDATER_ERROR_STRING); + UpdateIcon(eIcon_Error); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_ERROR_STRING)); + strFmt = m_ucChecker.GetLastError(); break; - case CUpdateChecker::eResult_RemoteVersionOlder: - TRACE(_T("CUpdateChecker::eResult_RemoteVersionOlder\n")); - eBkMode = eRes_Exit; - bEnableButton = true; -// eBkMode = eRes_Show; // for debugging purposes only - strFmt = rResManager.LoadString(IDS_UPDATER_OLD_VERSION_STRING); - break; + case CUpdateChecker::eResult_VersionCurrent: TRACE(_T("CUpdateChecker::eResult_VersionCurrent\n")); eBkMode = eRes_Exit; - bEnableButton = true; + bEnableButton = false; + UpdateIcon(eIcon_Info); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_ALREADYNEWESTVERSION)); strFmt = rResManager.LoadString(IDS_UPDATER_EQUAL_VERSION_STRING); break; + case CUpdateChecker::eResult_RemoteVersionNewer: TRACE(_T("CUpdateChecker::eResult_RemoteVersionNewer\n")); eBkMode = eRes_Show; bEnableButton = true; + UpdateIcon(eIcon_Warning); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_NEWVERSIONEXISTS)); strFmt = rResManager.LoadString(IDS_UPDATER_NEW_VERSION_STRING); break; + default: _ASSERTE(FALSE); eBkMode = eRes_Exit; @@ -145,12 +161,15 @@ fmt.SetFormat(strFmt); fmt.SetParam(_t("%site"), _t(PRODUCT_SITE)); - fmt.SetParam(_t("%errdesc"), m_ucChecker.GetLastError()); fmt.SetParam(_t("%thisver"), _T(PRODUCT_VERSION)); + fmt.SetParam(L"%numericver", PRODUCT_NUMERIC_VERSION); fmt.SetParam(_t("%officialver"), m_ucChecker.GetReadableVersion()); + fmt.SetParam(L"%reldate", m_ucChecker.GetReleaseDate()); - m_ctlText.SetWindowText(fmt); - + CString strEntireText = fmt; + strEntireText += L"\r\n\r\nRelease notes:\n" + CString(m_ucChecker.GetReleaseNotes()); + UpdateSecondaryText(strEntireText); + // Update button state CWnd* pWnd = GetDlgItem(IDC_OPEN_WEBPAGE_BUTTON); if(pWnd) @@ -181,3 +200,35 @@ CLanguageDialog::OnTimer(nIDEvent); } + +void CUpdaterDlg::UpdateIcon(EUpdateType eType) +{ + HICON hIcon = NULL; + switch(eType) + { + case eIcon_Warning: + hIcon = AfxGetApp()->LoadStandardIcon(IDI_WARNING); + break; + + case eIcon_Error: + hIcon = AfxGetApp()->LoadStandardIcon(IDI_ERROR); + break; + + case eIcon_Info: + default: + hIcon = AfxGetApp()->LoadStandardIcon(IDI_INFORMATION); + break; + } + + m_ctlImage.SetIcon(hIcon); +} + +void CUpdaterDlg::UpdateMainText(const wchar_t* pszText) +{ + m_ctlMainText.SetWindowText(pszText); +} + +void CUpdaterDlg::UpdateSecondaryText(const wchar_t* pszText) +{ + m_ctlRichEdit.SetWindowText(pszText); +} Index: src/ch/UpdaterDlg.h =================================================================== diff -u -N -rf34d204b8eecd6817dbe4a1c3b3541cf9a8794b0 -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/UpdaterDlg.h (.../UpdaterDlg.h) (revision f34d204b8eecd6817dbe4a1c3b3541cf9a8794b0) +++ src/ch/UpdaterDlg.h (.../UpdaterDlg.h) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -13,6 +13,14 @@ eRes_Exit, eRes_Show }; + + enum EUpdateType + { + eIcon_Info, + eIcon_Warning, + eIcon_Error + }; + public: CUpdaterDlg(bool bBackgroundMode, CWnd* pParent = NULL); // standard constructor virtual ~CUpdaterDlg(); @@ -30,8 +38,16 @@ DECLARE_MESSAGE_MAP() +private: + void UpdateIcon(EUpdateType eType); + void UpdateMainText(const wchar_t* pszText); + void UpdateSecondaryText(const wchar_t* pszText); + protected: - CStatic m_ctlText; + CStatic m_ctlMainText; + CStatic m_ctlImage; + CRichEditCtrl m_ctlRichEdit; + CUpdateChecker m_ucChecker; CUpdateChecker::ECheckResult m_eLastState; bool m_bBackgroundMode; ///< Do we operate in standard mode (false), or in background mode (true) Index: src/ch/WindowsVersion.cpp =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/WindowsVersion.cpp (.../WindowsVersion.cpp) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/ch/WindowsVersion.cpp (.../WindowsVersion.cpp) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -24,73 +24,96 @@ std::wstring WindowsVersion::GetWindowsVersion() { - TRegistry regCurrentVer(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"); + UpdateCachedData(); - std::wstring wstrVersion; - std::wstring wstrProductName; - std::wstring wstrInstallType; - std::wstring wstrBuildNumber; - std::wstring wstrServicePack; + std::wstring wstrShortInstallType; + if(m_wstrInstallType != L"Client" && !m_wstrInstallType.empty()) + wstrShortInstallType = m_wstrInstallType[ 0 ]; - DWORD dwMajor = 0; - DWORD dwMinor = 0; - if (regCurrentVer.QueryDword(L"CurrentMajorVersionNumber", dwMajor) && regCurrentVer.QueryDword(L"CurrentMinorVersionNumber", dwMinor)) - wstrVersion = boost::lexical_cast(dwMajor) + L"." + boost::lexical_cast(dwMinor); - else - { - if (!regCurrentVer.QueryString(L"CurrentVersion", wstrVersion)) - wstrVersion = L"Unknown version"; - } + std::wstring wstrFullVer = m_wstrProductName; + if (!m_wstrServicePack.empty()) + wstrFullVer += L" " + m_wstrServicePack; - if (regCurrentVer.QueryString(L"CurrentBuildNumber", wstrBuildNumber)) - wstrVersion += L"." + wstrBuildNumber; + wstrFullVer += L" (" + m_wstrVersion + wstrShortInstallType + L";" + m_wstrCpuArch + L")"; + return wstrFullVer; +} - regCurrentVer.QueryString(L"ProductName", wstrProductName); - if (regCurrentVer.QueryString(L"InstallationType", wstrInstallType) && !wstrInstallType.empty()) - { - if (wstrInstallType == L"Client") - wstrInstallType.clear(); - else - wstrInstallType = wstrInstallType[0]; - } +std::wstring WindowsVersion::GetWindowsVersionNumeric() +{ + UpdateCachedData(); + return m_wstrVersion; +} - regCurrentVer.QueryString(L"CSDVersion", wstrServicePack); - boost::replace_all(wstrServicePack, L"Service Pack ", L"SP"); +std::wstring WindowsVersion::GetWindowsVersionLongName() +{ + UpdateCachedData(); + return m_wstrProductName; +} - std::wstring wstrFullVer = wstrProductName; - if (!wstrServicePack.empty()) - wstrFullVer += L" " + wstrServicePack; - - wstrFullVer += L" (" + wstrVersion + wstrInstallType + L";" + GetCpuArch() + L")"; - return wstrFullVer; +std::wstring WindowsVersion::GetWindowsInstallType() +{ + UpdateCachedData(); + return m_wstrInstallType; } std::wstring WindowsVersion::GetCpuArch() { + UpdateCachedData(); + return m_wstrCpuArch; +} + +void WindowsVersion::UpdateCachedData() +{ + if(m_bCacheFilled) + return; + + TRegistry regCurrentVer(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"); + + DWORD dwMajor = 0; + DWORD dwMinor = 0; + if(regCurrentVer.QueryDword(L"CurrentMajorVersionNumber", dwMajor) && regCurrentVer.QueryDword(L"CurrentMinorVersionNumber", dwMinor)) + m_wstrVersion = boost::lexical_cast(dwMajor) + L"." + boost::lexical_cast(dwMinor); + else + { + if(!regCurrentVer.QueryString(L"CurrentVersion", m_wstrVersion)) + m_wstrVersion = L"Unknown version"; + } + + if(regCurrentVer.QueryString(L"CurrentBuildNumber", m_wstrBuildNumber)) + m_wstrVersion += L"." + m_wstrBuildNumber; + + regCurrentVer.QueryString(L"ProductName", m_wstrProductName); + regCurrentVer.QueryString(L"InstallationType", m_wstrInstallType); + regCurrentVer.QueryString(L"CSDVersion", m_wstrServicePack); + boost::replace_all(m_wstrServicePack, L"Service Pack ", L"SP"); + + // cpu/os arch SYSTEM_INFO si = { 0 }; GetNativeSystemInfo(&si); - switch (si.wProcessorArchitecture) + switch(si.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: { #ifndef _M_AMD64 - return L"x64-"; + m_wstrCpuArch = L"x64-"; #else - return L"x64"; + m_wstrCpuArch = L"x64"; #endif + break; } case PROCESSOR_ARCHITECTURE_INTEL: { #ifndef _M_IX86 - return L"x86-"; + m_wstrCpuArch = L"x86-"; #else - return L"x86"; + m_wstrCpuArch = L"x86"; #endif + break; } default: - return L"A" + boost::lexical_cast(si.wProcessorArchitecture); + m_wstrCpuArch = L"A" + boost::lexical_cast(si.wProcessorArchitecture); } } Index: src/ch/WindowsVersion.h =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/WindowsVersion.h (.../WindowsVersion.h) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/ch/WindowsVersion.h (.../WindowsVersion.h) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -24,8 +24,23 @@ class WindowsVersion { public: - static std::wstring GetWindowsVersion(); - static std::wstring GetCpuArch(); + std::wstring GetWindowsVersion(); + std::wstring GetWindowsVersionNumeric(); + std::wstring GetWindowsVersionLongName(); + std::wstring GetWindowsInstallType(); + std::wstring GetCpuArch(); + +private: + void UpdateCachedData(); + +private: + bool m_bCacheFilled = false; + std::wstring m_wstrVersion; + std::wstring m_wstrProductName; + std::wstring m_wstrInstallType; + std::wstring m_wstrBuildNumber; + std::wstring m_wstrServicePack; + std::wstring m_wstrCpuArch; }; #endif Index: src/ch/ch.rc =================================================================== diff -u -N -r2956a1b21d8af867e947907a038060a97932c37b -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/ch.rc (.../ch.rc) (revision 2956a1b21d8af867e947907a038060a97932c37b) +++ src/ch/ch.rc (.../ch.rc) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -39,8 +39,8 @@ ICON "",IDC_IMAGE_STATIC,13,13,21,20,SS_REALSIZEIMAGE CONTROL "Do not show this again",IDC_BASIC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,36,163,10 PUSHBUTTON "Btn1",IDC_FIRST_BUTTON,7,49,50,14 - CONTROL "",IDC_MSG_RICHEDIT,"RichEdit20W",ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_TABSTOP,43,13,127,20 - CONTROL "",IDC_MEASURE_RICHEDIT,"RichEdit20W",ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,7,7,11,7 + CONTROL "",IDC_MSG_RICHEDIT,"RichEdit20W",WS_DISABLED | WS_TABSTOP | 0x804,43,13,127,20 + CONTROL "",IDC_MEASURE_RICHEDIT,"RichEdit20W",NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP | 0x8c4,7,7,11,7 END IDD_BUFFERSIZE_DIALOG DIALOGEX 0, 0, 345, 135 @@ -379,14 +379,20 @@ EDITTEXT IDC_LOCATION_EDIT,119,65,190,46,ES_MULTILINE | ES_READONLY | NOT WS_BORDER END -IDD_UPDATER_DIALOG DIALOGEX 0, 0, 259, 83 +IDD_UPDATER_DIALOG DIALOGEX 0, 0, 305, 147 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Copy Handler Update Information" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "&Close",IDOK,202,62,50,14 - LTEXT "",IDC_INFO_STATIC,7,7,245,48 - PUSHBUTTON "&Download latest version...",IDC_OPEN_WEBPAGE_BUTTON,85,62,112,14 + DEFPUSHBUTTON "&Close",IDOK,248,126,50,14 + PUSHBUTTON "&Download latest version...",IDC_OPEN_WEBPAGE_BUTTON,130,126,112,14 + COMBOBOX IDC_COMBO1,159,101,139,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Update channel:",IDC_UPDATECHANNEL_STATIC,160,89,138,8 + LTEXT "Check for updates:",IDC_CHECKFORUPDATESFREQ_STATIC,7,89,62,8 + COMBOBOX IDC_COMBO2,7,101,142,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_CHANGELOG_RICHEDIT,"RichEdit20W",ES_MULTILINE | ES_READONLY | ES_NUMBER | WS_VSCROLL | WS_TABSTOP,51,25,247,56 + ICON "",IDC_ICON_STATIC,15,15,21,20 + CONTROL "Custom1",IDC_MAINUPDATEINFO_CUSTOM,"STATICEX",0x30,47,7,251,14 END IDD_FEEDBACK_REPLACE_DIALOG DIALOGEX 0, 0, 273, 159 @@ -533,9 +539,9 @@ IDD_UPDATER_DIALOG, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 252 + RIGHTMARGIN, 298 TOPMARGIN, 7 - BOTTOMMARGIN, 76 + BOTTOMMARGIN, 140 END IDD_FEEDBACK_REPLACE_DIALOG, DIALOG @@ -557,31 +563,56 @@ // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\ch.ico" + IDI_ERROR_ICON ICON "res\\error.ico" + IDI_WORKING_ICON ICON "res\\working.ico" + IDI_PAUSED_ICON ICON "res\\paused.ico" + IDI_FINISHED_ICON ICON "res\\finished.ico" + IDI_CANCELLED_ICON ICON "res\\cancelled.ico" + IDI_WAITING_ICON ICON "res\\waiting.ico" + IDI_QUESTION_ICON ICON "res\\question.ico" + IDI_INFO_ICON ICON "res\\info.ico" + IDI_ERR_ICON ICON "res\\err.ico" + IDI_WARNING_ICON ICON "res\\warning.ico" + IDI_SHUTDOWN_ICON ICON "res\\shut.ico" + IDI_NET_ICON ICON "res\\net.ico" + IDI_HDD_ICON ICON "res\\hd.ico" + IDI_CD_ICON ICON "res\\cd.ico" + IDI_HDD2_ICON ICON "res\\HD2.ICO" + IDI_TRIBE_ICON ICON "res\\tribe.ico" + IDI_FOLDER_ICON ICON "res\\folder.ico" + IDI_ADDSHORTCUT_ICON ICON "res\\addshort.ico" + IDI_DELETESHORTCUT_ICON ICON "res\\delshort.ico" + IDI_LARGEICONS_ICON ICON "res\\large.ico" + IDI_LIST_ICON ICON "res\\list.ico" + IDI_NEWFOLDER_ICON ICON "res\\newdir.ico" + IDI_REPORT_ICON ICON "res\\report.ico" + IDI_SMALLICONS_ICON ICON "res\\small.ico" + ///////////////////////////////////////////////////////////////////////////// // // Menu @@ -684,7 +715,12 @@ 0 END +IDD_UPDATER_DIALOG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // // String Table @@ -791,10 +827,11 @@ IDS_CFGINTERCEPTCONTEXTMENU_STRING "Intercept standard Windows operations (experimental/not recommended)" IDS_CFG_CHECK_FOR_UPDATES_FREQUENCY "Check for program updates" - IDS_CFG_UPDATE_CHECK_FOR_BETA "Check for updates - include beta versions" + IDS_CFG_UPDATECHANNEL "Update channel" IDS_CFGLOGLEVEL "Log level" IDS_CFGLOGLEVEL_VALUES "Debug!Info!Warning!Error" IDS_UPDATE_FREQUENCIES "Never!Every startup!Daily!Weekly!Once every 2 weeks!Monthly!Quarterly" + IDS_BUFFER_QUEUE_DEPTH "Buffer queue depth" END STRINGTABLE @@ -826,7 +863,6 @@ IDS_USENOBUFFERING_STRING "Disable buffering for large files" IDS_LARGEFILESMINSIZE_STRING "Minimum file size for which buffering should be turned off" - IDS_BUFFER_QUEUE_DEPTH "Buffer queue depth" IDS_OPTIONSBUFFER_STRING "Buffer" IDS_ONEDISKBUFFERSIZE_STRING "Buffer size for copying inside one physical disk boundary" @@ -890,6 +926,8 @@ IDS_STATUS_INITIALIZING_STRING "Initializing" IDS_STATUS_FASTMOVE_STRING "Fast moving" IDS_EMPTYSUBTASKNAME_STRING "none" + IDS_STATUS_LOADERROR_STRING "Load error" + IDS_EXPORTING_TASK_FAILED "Exporting task data failed. Reason: %reason." END STRINGTABLE @@ -899,7 +937,6 @@ IDS_STATUS_MOVING_STRING "Moving" IDS_STATUS_FINISHED_STRING "Finished" IDS_STATUS_ERROR_STRING "Error" - IDS_STATUS_LOADERROR_STRING "Load error" IDS_STATUS_PAUSED_STRING "Paused" IDS_STATUS_DELETING_STRING "Deleting" IDS_STATUS_UNKNOWN_STRING "Unknown" @@ -929,13 +966,27 @@ IDS_GE_STRING ">=" IDS_GT_STRING ">" IDS_UPDATER_NEW_VERSION_STRING - "There is a new version of Copy Handler available on the official web page.\n\nYour current version: %thisver\nVersion available on site: %officialver." - IDS_UPDATER_OLD_VERSION_STRING - "You have a newer version of Copy Handler than is available on the official web page.\n\nYour current version: %thisver\nVersion available on site: %officialver." + "Updated version: %officialver (%numericver).\nReleased: %reldate" END STRINGTABLE BEGIN + IDS_DIALOGS_SHOW_HIDE_STRING "Show/hide dialogs" + IDS_SHELLEXT_REGISTER_SHOWHIDE_STRING + "Show message about shell extension not registered" + IDS_SHELLEXT_VERSIONMISMATCH_SHOWHIDE_STRING + "Show message about shell extension version mismatch" + IDS_SHELLEXT_XML_IMPORT_FAILED + "Encountered an error when communicating with CH Shell Extension.\nDetails:\n%err" + IDS_UPDATER_NEWUPDATE_STRING "Updates are available" + IDS_UPDATER_CHECKINGFORUPDATES "Checking for updates..." + IDS_UPDATER_KILLEDERROR "Checking for updates was stopped" + IDS_UPDATER_ALREADYNEWESTVERSION "You already have the newest version" + IDS_UPDATER_NEWVERSIONEXISTS "There are updates available" +END + +STRINGTABLE +BEGIN IDS_BSONEDISK_STRING "One disk: " IDS_BSTWODISKS_STRING "Two disks: " IDS_BSCD_STRING "CD: " @@ -1036,12 +1087,16 @@ IDS_MENUTIPMOVETO_STRING "Moves selected data into specified folder" IDS_MENUTIPCOPYMOVETOSPECIAL_STRING "Copies/moves selected data into specified folder with additional settings" + IDS_SHELLEXT_CHOOSE_DIR_STRING "Choose directory..." + IDS_SHELLEXT_CHOOSE_DIR_TOOLTIP_STRING + "Allows to choose the destination directory" END STRINGTABLE BEGIN IDS_CFGFDSHORTCUTSSTYLES_STRING "Large icons!Small icons!List!Report" IDS_CFGPRIORITYCLASSITEMS_STRING "Idle!Normal!High!Real-time" + IDS_CFGUPDATECHANNELITEMS_STRING "Stable!Release Candidate!Beta!Alpha" IDS_PLUGSFOLDER_STRING "Folder with plugins" IDS_PLUGSFOLDERCHOOSE_STRING "!Choose folder with plugins" IDS_CFGLOGFILE_STRING "Debugging" @@ -1124,12 +1179,9 @@ STRINGTABLE BEGIN - IDS_UPDATER_EQUAL_VERSION_STRING - "You already have the newest version of Copy Handler.\n\nYour current version: %thisver\nVersion available on site: %officialver." - IDS_UPDATER_ERROR_STRING - "There was an error when trying to retrieve version information from the official web page (%errdesc)." - IDS_UPDATER_WAITING_STRING - "Please wait for the connection with %site to be established..." + IDS_UPDATER_EQUAL_VERSION_STRING "Your current version: %thisver" + IDS_UPDATER_ERROR_STRING "Check for updates error" + IDS_UPDATER_WAITING_STRING "Connecting with %site..." IDS_SHELL_EXTENSION_MISMATCH_STRING "Copy Handler detected an incompatible version of Shell Extension component.\nWould you like to update it now (requires administrative rights)?" IDS_SHELL_EXTENSION_UNREGISTERED_STRING @@ -1145,18 +1197,11 @@ IDS_ALWAYS_SHOW_STRING "Always show" IDS_HIDE_AND_REGISTER "Hide and register extension" IDS_HIDE_AND_DONT_REGISTER "Hide and do not register extension" - IDS_DIALOGS_SHOW_HIDE_STRING "Show/hide dialogs" - IDS_SHELLEXT_REGISTER_SHOWHIDE_STRING "Show message about shell extension not registered" - IDS_SHELLEXT_VERSIONMISMATCH_SHOWHIDE_STRING "Show message about shell extension version mismatch" - IDS_SHELLEXT_CHOOSE_DIR_STRING "Choose directory..." - IDS_SHELLEXT_CHOOSE_DIR_TOOLTIP_STRING "Allows to choose the destination directory" - IDS_SHELLEXT_XML_IMPORT_FAILED "Encountered an error when communicating with CH Shell Extension.\nDetails:\n%err" END STRINGTABLE BEGIN IDS_INFO_REASON_STRING "Reason: %reason" - IDS_EXPORTING_TASK_FAILED "Exporting task data failed. Reason: %reason." END #endif // English (United States) resources Index: src/ch/ch.vc140.vcxproj =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/ch.vc140.vcxproj (.../ch.vc140.vcxproj) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/ch/ch.vc140.vcxproj (.../ch.vc140.vcxproj) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -495,6 +495,7 @@ + @@ -539,8 +540,12 @@ + + + + Generating map file for help compiler... @@ -737,6 +742,7 @@ NotUsing + @@ -788,6 +794,8 @@ + + @@ -808,6 +816,8 @@ + + @@ -816,11 +826,9 @@ Compiling resources %(FullPath) "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" res/ch.rc2;version.h res/ch.rc2;version.h @@ -830,11 +838,9 @@ Compiling resources %(FullPath) "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" res/ch.rc2;version.h res/ch.rc2;version.h @@ -844,11 +850,9 @@ Compiling resources %(FullPath) "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" res/ch.rc2;version.h res/ch.rc2;version.h @@ -858,11 +862,9 @@ Compiling resources %(FullPath) "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" "$(SolutionDir)\tools\rc2lng.exe" "%(FullPath)" "$(InputDir)scripts\header.lng" "$(IntDir)\chtmp.rc" "$(OutDir)langs\english.lng" "$(InputDir)resource.h" "$(VCInstallDir)atlmfc\include\afxres.h" rc.exe /l 0x409 /d "NDEBUG" /d "_AFXDLL" /fo"$(OutDir)\%(Filename).res" "$(IntDir)\chtmp.rc" -del "$(IntDir)\chtmp.rc" res/ch.rc2;version.h res/ch.rc2;version.h Index: src/ch/ch.vc140.vcxproj.filters =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/ch.vc140.vcxproj.filters (.../ch.vc140.vcxproj.filters) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/ch/ch.vc140.vcxproj.filters (.../ch.vc140.vcxproj.filters) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -60,6 +60,9 @@ {1918eba7-24c6-47a0-8f86-d843a76e0e32} + + {2e2638f2-07f6-4472-bd2d-32151a7ef9ce} + @@ -98,9 +101,6 @@ Source Files\Tools - - Source Files\Tools - Source Files\Main @@ -215,6 +215,24 @@ Source Files\Tools + + Source Files\Tools + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + @@ -241,9 +259,6 @@ Source Files\Tools - - Source Files\Tools - Source Files\Main @@ -361,6 +376,24 @@ Source Files\Tools + + Source Files\Tools + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + + + Source Files\Tools\UpdateChecker + Index: src/ch/resource.h =================================================================== diff -u -N -r8592d6dcef30c8e4967ca4dcee37c1ca52afbf16 -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/ch/resource.h (.../resource.h) (revision 8592d6dcef30c8e4967ca4dcee37c1ca52afbf16) +++ src/ch/resource.h (.../resource.h) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -354,6 +354,16 @@ #define IDC_EXPORT_BUTTON 1322 #define IDC_BUFFERCOUNT_SPIN 1324 #define IDC_BUFFERCOUNT_EDIT 1325 +#define IDC_COMBO1 1325 +#define IDC_COMBO2 1326 +#define IDC_LIST1 1327 +#define IDC_RICHEDIT21 1329 +#define IDC_CHANGELOG_RICHEDIT 1329 +#define IDC_MAINUPDATEINFO_CUSTOM 1330 +#define IDC_ICON_STATIC 1331 +#define IDC_RELESENOTES_STATIC 1332 +#define IDC_CHECKFORUPDATESFREQ_STATIC 1333 +#define IDC_UPDATECHANNEL_STATIC 1334 #define IDS_APPNAME_STRING 5000 #define IDS_PRIORITY0_STRING 5001 #define IDS_PRIORITY1_STRING 5002 @@ -377,7 +387,6 @@ #define IDS_GE_STRING 5020 #define IDS_GT_STRING 5021 #define IDS_UPDATER_NEW_VERSION_STRING 5022 -#define IDS_UPDATER_OLD_VERSION_STRING 5023 #define IDS_UPDATER_EQUAL_VERSION_STRING 5024 #define IDS_UPDATER_ERROR_STRING 5025 #define IDS_UPDATER_WAITING_STRING 5026 @@ -396,6 +405,11 @@ #define IDS_SHELLEXT_REGISTER_SHOWHIDE_STRING 5041 #define IDS_SHELLEXT_VERSIONMISMATCH_SHOWHIDE_STRING 5042 #define IDS_SHELLEXT_XML_IMPORT_FAILED 5043 +#define IDS_UPDATER_NEWUPDATE_STRING 5044 +#define IDS_UPDATER_CHECKINGFORUPDATES 5045 +#define IDS_UPDATER_KILLEDERROR 5046 +#define IDS_UPDATER_ALREADYNEWESTVERSION 5047 +#define IDS_UPDATER_NEWVERSIONEXISTS 5048 #define IDS_ONECOPY_STRING 6000 #define IDS_REGISTEROK_STRING 6001 #define IDS_REGISTERERR_STRING 6002 @@ -481,6 +495,7 @@ #define IDS_FORCESHUTDOWNVALUES_STRING 8079 #define IDS_CFGFDSHORTCUTSSTYLES_STRING 8080 #define IDS_CFGPRIORITYCLASSITEMS_STRING 8081 +#define IDS_CFGUPDATECHANNELITEMS_STRING 8082 #define IDS_PLUGSFOLDER_STRING 8083 #define IDS_PLUGSFOLDERCHOOSE_STRING 8084 #define IDS_CFGLOGFILE_STRING 8085 @@ -493,7 +508,7 @@ #define IDS_ABOUT_LANGUAGE_STRING 8095 #define IDS_CFGINTERCEPTCONTEXTMENU_STRING 8096 #define IDS_CFG_CHECK_FOR_UPDATES_FREQUENCY 8097 -#define IDS_CFG_UPDATE_CHECK_FOR_BETA 8098 +#define IDS_CFG_UPDATECHANNEL 8098 #define IDS_CFGLOGLEVEL 8099 #define IDS_CFGLOGLEVEL_VALUES 8100 #define IDS_UPDATE_FREQUENCIES 8101 @@ -677,9 +692,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 218 +#define _APS_NEXT_RESOURCE_VALUE 219 #define _APS_NEXT_COMMAND_VALUE 32819 -#define _APS_NEXT_CONTROL_VALUE 1325 +#define _APS_NEXT_CONTROL_VALUE 1335 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif Index: src/common/version.h =================================================================== diff -u -N -rd5fd15320ef765fd5225b10e764bca458c2e317c -r50ad2dc9f0b42ba432bb54e4a042582277410773 --- src/common/version.h (.../version.h) (revision d5fd15320ef765fd5225b10e764bca458c2e317c) +++ src/common/version.h (.../version.h) (revision 50ad2dc9f0b42ba432bb54e4a042582277410773) @@ -14,8 +14,15 @@ #define PRODUCT_VERSION3 724 #define PRODUCT_VERSION4 0 +#define PRODUCT_FULL_NUMERIC_VERSION ((unsigned long long)PRODUCT_VERSION1) << 48 | ((unsigned long long)PRODUCT_VERSION2) << 32 | ((unsigned long long)PRODUCT_VERSION3) << 16 | ((unsigned long long)PRODUCT_VERSION4) + #define PRODUCT_VERSION "1.40internal-svn724" +#define STRINGIZE2(a) STRINGIZE(a) +#define STRINGIZE(a) L#a + +#define PRODUCT_NUMERIC_VERSION STRINGIZE2(PRODUCT_VERSION1) L"." STRINGIZE2(PRODUCT_VERSION2) L"." STRINGIZE2(PRODUCT_VERSION3) L"." STRINGIZE2(PRODUCT_VERSION4) + #if SETUP_COMPILER != 1 #define SHELLEXT_PRODUCT_FULL_VERSION SHELLEXT_PRODUCT_NAME " " PRODUCT_VERSION #define SHELLEXT_PRODUCT_FULL_VERSION_T _T(SHELLEXT_PRODUCT_NAME) _T(" ") _T(PRODUCT_VERSION)