Update check logic moved to standalone DLL to make it reusable
This commit is contained in:
parent
54e64515d4
commit
529bd00da5
@ -82,6 +82,7 @@ s38 s$(MSIBUILD_LENGTH_ID)
|
||||
FeatureComponents Feature_ Component_
|
||||
featUpdCheck compUpdCheck.exe.$(PLAT)
|
||||
featUpdCheck compwxExtend.dll.$(PLAT)
|
||||
featUpdCheck compUpdater.dll.$(PLAT)
|
||||
<<NOKEEP
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\lib\wxExtend\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Updater\include;..\..\lib\wxExtend\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
</ItemDefinitionGroup>
|
||||
|
Binary file not shown.
@ -85,7 +85,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="UpdCheck.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="UpdCheck.rc" />
|
||||
@ -103,6 +102,9 @@
|
||||
<ProjectReference Include="..\..\lib\wxExtend\build\wxExtend.vcxproj">
|
||||
<Project>{a3a36689-ac35-4026-93da-a3ba0c0e767c}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Updater\build\Updater.vcxproj">
|
||||
<Project>{990d8cf9-4457-4dc0-aa18-4968ef434741}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -30,9 +30,6 @@
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UpdCheck.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="UpdCheck.rc">
|
||||
|
@ -2,7 +2,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: UpdCheck\n"
|
||||
"POT-Creation-Date: 2016-05-13 19:52+0200\n"
|
||||
"POT-Creation-Date: 2016-05-24 13:24+0200\n"
|
||||
"PO-Revision-Date: 2016-03-30 11:37+0200\n"
|
||||
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
|
||||
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
|
||||
@ -18,33 +18,45 @@ msgstr ""
|
||||
"X-Poedit-KeywordsList: _\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: MSIBuild/En.Win32.Debug.ScheduledTask-2.idtx:4
|
||||
#: MSIBuild/En.Win32.Release.ScheduledTask-2.idtx:4
|
||||
#: MSIBuild/En.x64.Debug.ScheduledTask-2.idtx:4
|
||||
#: MSIBuild/En.x64.Release.ScheduledTask-2.idtx:4
|
||||
#, fuzzy
|
||||
msgid "[SimpleProductName] Update"
|
||||
msgstr "Posodabljanje [SimpleProductName]"
|
||||
|
||||
#: MSIBuild/En.Win32.Debug.Feature-2.idtx:3
|
||||
#: MSIBuild/En.Win32.Debug.ScheduledTask-2.idtx:3
|
||||
#: MSIBuild/En.Win32.Release.Feature-2.idtx:3
|
||||
#: MSIBuild/En.Win32.Release.ScheduledTask-2.idtx:3
|
||||
#: MSIBuild/En.x64.Debug.Feature-2.idtx:3
|
||||
#: MSIBuild/En.x64.Debug.ScheduledTask-2.idtx:3
|
||||
#: MSIBuild/En.x64.Release.Feature-2.idtx:3
|
||||
#: MSIBuild/En.x64.Release.ScheduledTask-2.idtx:3
|
||||
#, fuzzy
|
||||
msgid "1252"
|
||||
msgstr "1250"
|
||||
|
||||
#: MSIBuild/En.Win32.Debug.Feature-2.idtx:4
|
||||
#: MSIBuild/En.Win32.Release.Feature-2.idtx:4
|
||||
#: MSIBuild/En.x64.Debug.Feature-2.idtx:4
|
||||
#: MSIBuild/En.x64.Release.Feature-2.idtx:4
|
||||
#, fuzzy
|
||||
msgid "Automatic Updating"
|
||||
msgstr "Samodejno posodabljanje"
|
||||
|
||||
#: MSIBuild/En.Win32.Debug.ScheduledTask-2.idtx:4
|
||||
#: MSIBuild/En.Win32.Release.ScheduledTask-2.idtx:4
|
||||
#: MSIBuild/En.x64.Debug.ScheduledTask-2.idtx:4
|
||||
#: MSIBuild/En.x64.Release.ScheduledTask-2.idtx:4
|
||||
#, fuzzy
|
||||
msgid "Regularly checks for program updates, downloads, and installs them"
|
||||
msgstr "Redno preverja za posodobitve programa, prenese in jih namesti"
|
||||
|
||||
#: MSIBuild/En.Win32.Debug.Feature-2.idtx:4
|
||||
#: MSIBuild/En.Win32.Release.Feature-2.idtx:4
|
||||
#: MSIBuild/En.x64.Debug.Feature-2.idtx:4
|
||||
#: MSIBuild/En.x64.Release.Feature-2.idtx:4
|
||||
#, fuzzy
|
||||
msgid "Task for background product updating"
|
||||
|
@ -20,558 +20,6 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
///
|
||||
/// UpdCheck Application
|
||||
///
|
||||
class wxUpdCheckApp
|
||||
{
|
||||
public:
|
||||
wxUpdCheckApp();
|
||||
virtual ~wxUpdCheckApp();
|
||||
|
||||
///
|
||||
/// Application's main method
|
||||
///
|
||||
/// \returns Return code
|
||||
///
|
||||
int Run();
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Downloads repository database (with integrity check).
|
||||
///
|
||||
/// \returns Repository database. Use wxDELETE after use.
|
||||
///
|
||||
wxXmlDocument* GetCatalogue();
|
||||
|
||||
///
|
||||
/// Parses repository database.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if parsing succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool ParseCatalogue(const wxXmlDocument &doc);
|
||||
|
||||
|
||||
///
|
||||
/// Stores update package meta-information to cache.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if writing succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool WriteUpdatePackageMeta();
|
||||
|
||||
///
|
||||
/// Retrieves update package meta-information from cache.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if reading succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool ReadUpdatePackageMeta();
|
||||
|
||||
///
|
||||
/// Downloads update package.
|
||||
///
|
||||
/// \param[in] fileName File name to save downloaded package to
|
||||
///
|
||||
/// \returns
|
||||
/// - true if downloading succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool DownloadUpdatePackage(const wxString &fileName);
|
||||
|
||||
///
|
||||
/// Launch update.
|
||||
///
|
||||
/// \param[in] fileName File name of the update package
|
||||
///
|
||||
/// \returns
|
||||
/// - true if launch succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool LaunchUpdate(const wxString &fileName);
|
||||
|
||||
|
||||
protected:
|
||||
bool m_ok; ///< Is class initialized correctly
|
||||
wxConfig m_config; ///< Application configuration
|
||||
wxString m_path; ///< Working directory (log, downloaded files, etc.)
|
||||
wxFFile m_log; ///< Log file
|
||||
wxLocale m_locale; ///< Current locale
|
||||
wxCryptoSession *m_cs; ///< Cryptographics session
|
||||
wxCryptoKey *m_ck; ///< Public key for update database integrity validation
|
||||
|
||||
wxUint32 m_version; ///< Latest product version available (numerical)
|
||||
wxString m_versionStr; ///< Latest product version available (string)
|
||||
wxArrayString m_urls; ///< List of update package file downloads
|
||||
wxMemoryBuffer m_hash; ///< Update package SHA-1 hash
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// wxUpdCheckApp
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
wxUpdCheckApp::wxUpdCheckApp() :
|
||||
m_config(wxT(UPDATER_CFG_APPLICATION) wxT("\\Updater"), wxT(UPDATER_CFG_VENDOR)),
|
||||
m_cs(NULL),
|
||||
m_ck(NULL),
|
||||
m_version(0)
|
||||
{
|
||||
m_path = wxFileName::GetTempDir();
|
||||
if (!wxEndsWithPathSeparator(m_path))
|
||||
m_path += wxFILE_SEP_PATH;
|
||||
|
||||
if (!wxDirExists(m_path))
|
||||
wxMkdir(m_path);
|
||||
|
||||
m_log.Open(m_path + wxT("Updater-") wxT(UPDATER_CFG_APPLICATION) wxT(".log"), wxT("wt"));
|
||||
if (m_log.IsOpened())
|
||||
delete wxLog::SetActiveTarget(new wxLogStderr(m_log.fp()));
|
||||
|
||||
// Set desired locale.
|
||||
wxLanguage language = (wxLanguage)m_config.Read(wxT("Language"), wxLANGUAGE_DEFAULT);
|
||||
if (wxLocale::IsAvailable(language))
|
||||
wxVERIFY(m_locale.Init(language));
|
||||
|
||||
wxASSERT_MSG(!m_cs, wxT("cryptographics session already initialized"));
|
||||
m_cs = new wxCryptoSessionRSAAES();
|
||||
wxCHECK2_MSG(m_cs, { m_ok = false; return; }, wxT("wxCryptoSessionRSAAES creation failed"));
|
||||
|
||||
// Import public key.
|
||||
HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(IDR_KEY_PUBLIC), RT_RCDATA);
|
||||
wxCHECK2_MSG(res, { m_ok = false; return; }, wxT("public key not found"));
|
||||
HGLOBAL res_handle = ::LoadResource(NULL, res);
|
||||
wxCHECK2_MSG(res_handle, { m_ok = false; return; }, wxT("loading resource failed"));
|
||||
|
||||
m_ck = new wxCryptoKey();
|
||||
wxCHECK2_MSG(m_ck, { m_ok = false; return; }, wxT("wxCryptoKey creation failed"));
|
||||
wxCHECK2(m_ck->ImportPublic(*m_cs, ::LockResource(res_handle), ::SizeofResource(NULL, res)), { m_ok = false; return; });
|
||||
}
|
||||
|
||||
|
||||
wxUpdCheckApp::~wxUpdCheckApp()
|
||||
{
|
||||
if (m_ck) delete m_ck;
|
||||
if (m_cs) delete m_cs;
|
||||
}
|
||||
|
||||
|
||||
int wxUpdCheckApp::Run()
|
||||
{
|
||||
if (!m_ok)
|
||||
return -1; // Initialization failed.
|
||||
|
||||
// Download update catalogue.
|
||||
wxXmlDocument *doc = GetCatalogue();
|
||||
if (doc) {
|
||||
// Parse the update catalogue to check for an update package availability.
|
||||
if (ParseCatalogue(*doc)) {
|
||||
// Save update package meta-information for the next time.
|
||||
WriteUpdatePackageMeta();
|
||||
} else {
|
||||
wxLogStatus(wxT("Update check complete. Your package is up to date."));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Update download catalogue failed, or repository database didn't change. Read a cached version of update package meta-information?
|
||||
if (!ReadUpdatePackageMeta()) {
|
||||
// Reset CatalogueLastModified to force update catalogue download next time.
|
||||
m_config.DeleteEntry(wxT("CatalogueLastModified"));
|
||||
return 1; // No update package information available.
|
||||
}
|
||||
|
||||
if (m_version <= UPDATER_PRODUCT_VERSION) {
|
||||
wxLogStatus(wxT("Update check complete. Your package is up to date."));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
wxString fileName(m_path);
|
||||
fileName += wxT("Updater-") wxT(UPDATER_CFG_APPLICATION) wxT("-");
|
||||
fileName += m_versionStr;
|
||||
fileName += wxT(".msi");
|
||||
|
||||
if (!DownloadUpdatePackage(fileName))
|
||||
return 2; // Update package not available.
|
||||
|
||||
if (!LaunchUpdate(fileName))
|
||||
return 3; // Update launch failed.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
wxXmlDocument* wxUpdCheckApp::GetCatalogue()
|
||||
{
|
||||
wxLogStatus(wxT("Downloading repository catalogue..."));
|
||||
|
||||
wxString lastModified;
|
||||
m_config.Read(wxT("CatalogueLastModified"), &lastModified, wxT(""));
|
||||
|
||||
for (const wxChar *server = wxT(UPDATER_HTTP_SERVER); server[0]; server += wcslen(server) + 1) {
|
||||
wxLogStatus(wxT("Contacting repository at %s..."), server);
|
||||
|
||||
// Load repository database.
|
||||
wxHTTP http;
|
||||
http.SetHeader(wxS("User-Agent"), wxS("Updater/") wxS(UPDATER_VERSION_STR));
|
||||
if (!lastModified.IsEmpty())
|
||||
http.SetHeader(wxS("If-Modified-Since"), lastModified);
|
||||
if (!http.Connect(server, UPDATER_HTTP_PORT)) {
|
||||
wxLogWarning(wxT("Error resolving %s server name."), server);
|
||||
continue;
|
||||
}
|
||||
wxInputStream *httpStream = http.GetInputStream(wxS(UPDATER_HTTP_PATH));
|
||||
if (http.GetResponse() == 304) {
|
||||
wxLogStatus(wxT("Repository did not change since the last time."));
|
||||
wxDELETE(httpStream);
|
||||
return NULL;
|
||||
} else if (!httpStream) {
|
||||
wxLogWarning(wxT("Error response received from server %s (port %u) requesting %s."), server, UPDATER_HTTP_PORT, UPDATER_HTTP_PATH);
|
||||
continue;
|
||||
}
|
||||
wxXmlDocument *doc = new wxXmlDocument();
|
||||
if (!doc->Load(*httpStream, "UTF-8", wxXMLDOC_KEEP_WHITESPACE_NODES)) {
|
||||
wxLogWarning(wxT("Error loading repository catalogue."));
|
||||
wxDELETE(httpStream);
|
||||
http.Close();
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
wxDELETE(httpStream);
|
||||
m_config.Write(wxT("CatalogueLastModified"), http.GetHeader(wxT("Last-Modified")));
|
||||
http.Close();
|
||||
|
||||
wxLogStatus(wxT("Verifying repository catalogue signature..."));
|
||||
|
||||
// Find the (first) signature.
|
||||
wxXmlNode *document = doc->GetDocumentNode();
|
||||
wxMemoryBuffer sig;
|
||||
for (wxXmlNode *prolog = document->GetChildren(); prolog; prolog = prolog->GetNext()) {
|
||||
if (prolog->GetType() == wxXML_COMMENT_NODE) {
|
||||
wxString content = prolog->GetContent();
|
||||
size_t content_len = content.length();
|
||||
if (content_len >= _countof(wxS(UPDATER_SIGNATURE_MARK)) - 1 &&
|
||||
memcmp((const wxStringCharType*)content, wxS(UPDATER_SIGNATURE_MARK), sizeof(wxStringCharType)*(_countof(wxS(UPDATER_SIGNATURE_MARK)) - 1)) == 0)
|
||||
{
|
||||
// Read the signature.
|
||||
size_t signature_len = content_len - (_countof(wxS(UPDATER_SIGNATURE_MARK)) - 1);
|
||||
size_t len = wxBase64DecodedSize(signature_len);
|
||||
size_t res = wxBase64Decode(sig.GetWriteBuf(len), len, content.Right(signature_len), wxBase64DecodeMode_SkipWS);
|
||||
if (res != wxCONV_FAILED) {
|
||||
sig.SetDataLen(res);
|
||||
|
||||
// Remove the signature as it is not a part of the validation check.
|
||||
document->RemoveChild(prolog);
|
||||
wxDELETE(prolog);
|
||||
break;
|
||||
} else
|
||||
sig.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sig.IsEmpty()) {
|
||||
wxLogWarning(wxT("Signature not found in the repository catalogue."));
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hash the content.
|
||||
wxCryptoHashSHA1 ch(*m_cs);
|
||||
if (!wxXmlHashNode(ch, document)) {
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have the hash, we have the signature, we have the public key. Now verify.
|
||||
if (!wxCryptoVerifySignature(ch, sig, *m_ck)) {
|
||||
wxLogWarning(wxT("Repository catalogue signature does not match its content, or signature verification failed."));
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify document type (root element).
|
||||
const wxString &nameRoot = doc->GetRoot()->GetName();
|
||||
if (nameRoot != wxT("Packages")) {
|
||||
wxLogWarning(wxT("Invalid root element in repository catalogue (actual: %s, expected %s)."), nameRoot.c_str(), wxT("Packages"));
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The downloaded repository database passed all checks.
|
||||
return doc;
|
||||
}
|
||||
|
||||
// No repository database downloaded successfully.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckApp::ParseCatalogue(const wxXmlDocument &doc)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
wxLogStatus(wxT("Parsing repository catalogue..."));
|
||||
|
||||
// Iterate over packages.
|
||||
for (wxXmlNode *elPackage = doc.GetRoot()->GetChildren(); elPackage; elPackage = elPackage->GetNext()) {
|
||||
if (elPackage->GetType() == wxXML_ELEMENT_NODE && elPackage->GetName() == wxT("Package")) {
|
||||
// Get package version.
|
||||
wxUint32 version = 0;
|
||||
wxString versionStr;
|
||||
for (wxXmlNode *elVersion = elPackage->GetChildren(); elVersion; elVersion = elVersion->GetNext()) {
|
||||
if (elVersion->GetType() == wxXML_ELEMENT_NODE && elVersion->GetName() == wxT("Version")) {
|
||||
for (wxXmlNode *elVersionNote = elVersion->GetChildren(); elVersionNote; elVersionNote = elVersionNote->GetNext()) {
|
||||
if (elVersionNote->GetType() == wxXML_ELEMENT_NODE) {
|
||||
const wxString &name = elVersionNote->GetName();
|
||||
if (name == wxT("hex"))
|
||||
version = _tcstoul(elVersionNote->GetNodeContent(), NULL, 16);
|
||||
else if (name == wxT("desc"))
|
||||
versionStr = elVersionNote->GetNodeContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version <= UPDATER_PRODUCT_VERSION || version < m_version) {
|
||||
// This package is older than currently installed product or the superseeded package found already.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get package download URL for our platform and language.
|
||||
wxString platformId;
|
||||
#if defined(__WINDOWS__)
|
||||
platformId += wxT("win");
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
platformId += wxT("-amd64");
|
||||
#else
|
||||
platformId += wxT("-x86");
|
||||
#endif
|
||||
wxString languageId(m_locale.GetCanonicalName());
|
||||
wxArrayString urls;
|
||||
wxMemoryBuffer hash;
|
||||
for (wxXmlNode *elDownloads = elPackage->GetChildren(); elDownloads; elDownloads = elDownloads->GetNext()) {
|
||||
if (elDownloads->GetType() == wxXML_ELEMENT_NODE && elDownloads->GetName() == wxT("Downloads")) {
|
||||
for (wxXmlNode *elPlatform = elDownloads->GetChildren(); elPlatform; elPlatform = elPlatform->GetNext()) {
|
||||
if (elPlatform->GetType() == wxXML_ELEMENT_NODE) {
|
||||
if (elPlatform->GetName() == wxT("Platform") && elPlatform->GetAttribute(wxT("id")) == platformId) {
|
||||
// Get language.
|
||||
for (wxXmlNode *elLocale = elPlatform->GetChildren(); elLocale; elLocale = elLocale->GetNext()) {
|
||||
if (elLocale->GetType() == wxXML_ELEMENT_NODE && elLocale->GetName() == wxT("Localization") && elLocale->GetAttribute(wxT("lang")) == languageId) {
|
||||
for (wxXmlNode *elLocaleNote = elLocale->GetChildren(); elLocaleNote; elLocaleNote = elLocaleNote->GetNext()) {
|
||||
if (elLocaleNote->GetType() == wxXML_ELEMENT_NODE) {
|
||||
const wxString &name = elLocaleNote->GetName();
|
||||
if (name == wxT("url"))
|
||||
urls.Add(elLocaleNote->GetNodeContent());
|
||||
else if (name == wxT("hash")) {
|
||||
// Read the hash.
|
||||
wxString content(elLocaleNote->GetNodeContent());
|
||||
size_t len = wxHexDecodedSize(content.length());
|
||||
size_t res = wxHexDecode(hash.GetWriteBuf(len), len, content, wxHexDecodeMode_SkipWS);
|
||||
if (res != wxCONV_FAILED)
|
||||
hash.SetDataLen(res);
|
||||
else
|
||||
hash.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (urls.empty() || hash.IsEmpty()) {
|
||||
// This package is for different architecture and/or language.
|
||||
// ... or missing URL and/or hash.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save found package info.
|
||||
m_version = version;
|
||||
m_versionStr = versionStr;
|
||||
m_urls = urls;
|
||||
m_hash = hash;
|
||||
found = true;
|
||||
|
||||
wxLogMessage(wxT("Update package found (version: %s)."), m_versionStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckApp::WriteUpdatePackageMeta()
|
||||
{
|
||||
// Concatenate URLs.
|
||||
wxString urls;
|
||||
for (size_t i = 0, n = m_urls.GetCount(); i < n; i++) {
|
||||
if (i) urls += wxT('\n');
|
||||
urls += m_urls[i];
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
if (!m_config.Write(wxT("PackageVersion" ), m_version )) result = false;
|
||||
if (!m_config.Write(wxT("PackageVersionDesc"), m_versionStr )) result = false;
|
||||
if (!m_config.Write(wxT("PackageURLs" ), urls )) result = false;
|
||||
if (!m_config.Write(wxT("PackageHash" ), wxHexEncode(m_hash))) result = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckApp::ReadUpdatePackageMeta()
|
||||
{
|
||||
long lng;
|
||||
if (m_config.Read(wxT("PackageVersion"), &lng)) {
|
||||
m_version = lng;
|
||||
if (m_config.Read(wxT("PackageVersionDesc"), &m_versionStr)) {
|
||||
wxString str;
|
||||
if (m_config.Read(wxT("PackageURLs"), &str)) {
|
||||
// Split URLs
|
||||
m_urls.Clear();
|
||||
const wxStringCharType *buf = str;
|
||||
for (size_t i = 0, j = 0, n = str.Length(); i < n;) {
|
||||
for (; j < n && buf[j] != wxT('\n'); j++);
|
||||
m_urls.Add(str.SubString(i, j - 1));
|
||||
i = ++j;
|
||||
}
|
||||
|
||||
if (m_config.Read(wxT("PackageHash"), &str)) {
|
||||
// Convert to binary.
|
||||
size_t len = wxHexDecodedSize(str.length());
|
||||
size_t res = wxHexDecode(m_hash.GetWriteBuf(len), len, str, wxHexDecodeMode_SkipWS);
|
||||
if (res != wxCONV_FAILED) {
|
||||
m_hash.SetDataLen(res);
|
||||
return true;
|
||||
} else
|
||||
m_hash.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxLogWarning(wxT("Reading update package meta-information from cache failed or incomplete."));
|
||||
m_version = 0;
|
||||
m_versionStr.Clear();
|
||||
m_urls.Clear();
|
||||
m_hash.Clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckApp::DownloadUpdatePackage(const wxString &fileName)
|
||||
{
|
||||
// Calculate file hash (if exists).
|
||||
wxCryptoHashSHA1 ch(*m_cs);
|
||||
if (ch.HashFile(fileName)) {
|
||||
wxMemoryBuffer buf;
|
||||
ch.GetValue(buf);
|
||||
|
||||
if (buf.GetDataLen() == m_hash.GetDataLen() &&
|
||||
memcmp(buf.GetData(), m_hash.GetData(), buf.GetDataLen()) == 0)
|
||||
{
|
||||
// Update package file exists and its hash is correct.
|
||||
wxLogStatus(wxT("Update package file already downloaded."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
wxFFile file(fileName, wxT("wb"));
|
||||
if (!file.IsOpened()) {
|
||||
wxLogError(wxT("Can not open/create %s file for writing."), fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Download update package file.
|
||||
for (size_t i = 0, n = m_urls.GetCount(); i < n; i++) {
|
||||
wxURL url(m_urls[i]);
|
||||
if (!url.IsOk())
|
||||
continue;
|
||||
|
||||
if (url.HasScheme()) {
|
||||
const wxString scheme = url.GetScheme();
|
||||
if (scheme == wxT("http") || scheme == wxT("https")) {
|
||||
wxHTTP &http = (wxHTTP&)url.GetProtocol();
|
||||
http.SetHeader(wxS("User-Agent"), wxS("Updater/") wxS(UPDATER_VERSION_STR));
|
||||
}
|
||||
}
|
||||
|
||||
wxLogStatus(wxT("Downloading update package from %s..."), m_urls[i].c_str());
|
||||
wxInputStream *stream = url.GetInputStream();
|
||||
if (!stream) {
|
||||
wxLogWarning(wxT("Error response received."));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save update package to file, and calculate hash.
|
||||
wxCryptoHashSHA1 ch(*m_cs);
|
||||
wxMemoryBuffer buf(4*1024);
|
||||
char *data = (char*)buf.GetData();
|
||||
size_t nBlock = buf.GetBufSize();
|
||||
do {
|
||||
stream->Read(data, nBlock);
|
||||
size_t nRead = stream->LastRead();
|
||||
file.Write(data, nRead);
|
||||
if (file.Error()) {
|
||||
wxLogError(wxT("Can not write to %s file."), fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
ch.Hash(data, nRead);
|
||||
} while (stream->IsOk());
|
||||
ch.GetValue(buf);
|
||||
|
||||
if (buf.GetDataLen() == m_hash.GetDataLen() &&
|
||||
memcmp(buf.GetData(), m_hash.GetData(), buf.GetDataLen()) == 0)
|
||||
{
|
||||
// Update package file downloaded and its hash is correct.
|
||||
return true;
|
||||
} else
|
||||
wxLogWarning(wxT("Update package file corrupt."));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckApp::LaunchUpdate(const wxString &fileName)
|
||||
{
|
||||
wxLogStatus(wxT("Launching update..."));
|
||||
|
||||
// Headless Install
|
||||
wxString param("/qn");
|
||||
|
||||
// Package
|
||||
param += wxT(" /i \"");
|
||||
param += fileName;
|
||||
param += wxT("\"");
|
||||
|
||||
// Logging
|
||||
wxString fileNameLog(m_path);
|
||||
fileNameLog += wxT("Updater-") wxT(UPDATER_CFG_APPLICATION) wxT("-msiexec.log");
|
||||
|
||||
param += wxT(" /l* \"");
|
||||
param += fileNameLog;
|
||||
param += wxT("\"");
|
||||
|
||||
int result = (int)::ShellExecute(NULL, NULL, wxT("msiexec.exe"), param, NULL, SW_SHOWNORMAL);
|
||||
if (result > 32) {
|
||||
wxLogStatus(wxT("msiexec.exe launch succeeded. For further information, see %s file."), fileNameLog.c_str());
|
||||
return true;
|
||||
} else {
|
||||
wxLogError(wxT("msiexec.exe launch failed. ShellExecute returned %i."), result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Main function
|
||||
///
|
||||
@ -584,7 +32,34 @@ int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In
|
||||
if (!initializer.IsOk())
|
||||
return -1;
|
||||
|
||||
// Do everything.
|
||||
wxUpdCheckApp app;
|
||||
return app.Run();
|
||||
// Create output folder.
|
||||
wxString path(wxFileName::GetTempDir());
|
||||
if (!wxEndsWithPathSeparator(path))
|
||||
path += wxFILE_SEP_PATH;
|
||||
if (!wxDirExists(path))
|
||||
wxMkdir(path);
|
||||
|
||||
// Prepare log file.
|
||||
wxFFile log_file(path + wxT("Updater-") wxT(UPDATER_CFG_APPLICATION) wxT(".log"), wxT("wt"));
|
||||
if (log_file.IsOpened())
|
||||
delete wxLog::SetActiveTarget(new wxLogStderr(log_file.fp()));
|
||||
|
||||
// Set desired locale.
|
||||
wxConfig config(wxT(UPDATER_CFG_APPLICATION) wxT("\\Updater"), wxT(UPDATER_CFG_VENDOR));
|
||||
wxLanguage language = (wxLanguage)config.Read(wxT("Language"), wxLANGUAGE_DEFAULT);
|
||||
wxLocale locale;
|
||||
if (wxLocale::IsAvailable(language)) {
|
||||
wxVERIFY(locale.Init(language));
|
||||
// Do not add translation catalog, to keep log messages in English.
|
||||
// Log files are for help-desk and should remain globally intelligible.
|
||||
//wxVERIFY(locale.AddCatalog(wxT("Updater") wxT(wxExtendVersion)));
|
||||
}
|
||||
|
||||
wxUpdCheckThread worker(locale.GetCanonicalName());
|
||||
wxUpdCheckThread::wxResult res = worker.CheckForUpdate();
|
||||
switch (res) {
|
||||
case wxUpdCheckThread::wxUpdUpdateAvailable: return worker.LaunchUpdate() ? 0 : 1;
|
||||
case wxUpdCheckThread::wxUpdUpToDate : return 0;
|
||||
default : return res;
|
||||
}
|
||||
}
|
||||
|
@ -19,23 +19,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/UpdaterCfg.h"
|
||||
|
||||
#include "UpdCheck.h"
|
||||
#include "../include/Updater.h"
|
||||
#include <Updater/chkthread.h>
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/base64.h>
|
||||
#include <wx/buffer.h>
|
||||
#include <wx/config.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/ffile.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/protocol/http.h>
|
||||
#include <wx/url.h>
|
||||
#include <wx/xml/xml.h>
|
||||
#include <wx/init.h>
|
||||
|
||||
#include <wxex/crypto.h>
|
||||
#include <wxex/hex.h>
|
||||
#include <wxex/xml.h>
|
||||
#include <wxex/common.h>
|
||||
|
Binary file not shown.
@ -19,10 +19,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/UpdaterCfg.h"
|
||||
#include "../Updater/include/Updater/common.h"
|
||||
|
||||
#include "UpdPublish.h"
|
||||
#include "../include/Updater.h"
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/base64.h>
|
||||
|
Binary file not shown.
@ -19,8 +19,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Updater/include/Updater/common.h"
|
||||
|
||||
#include "UpdSignXML.h"
|
||||
#include "../include/Updater.h"
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/base64.h>
|
||||
|
16
Updater.sln
16
Updater.sln
@ -3,11 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{A7D28E0C-BB96-444D-AAB0-F22A6483FE5F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ECE3F336-FFD2-41EE-AD8F-17BD7472BDCB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
include\Updater.h = include\Updater.h
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdCheck", "UpdCheck\UpdCheck.vcxproj", "{0B2B7A10-3FA0-46CD-AD89-6D02DA2C5FC3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxExtend", "..\lib\wxExtend\build\wxExtend.vcxproj", "{A3A36689-AC35-4026-93DA-A3BA0C0E767C}"
|
||||
@ -16,6 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdSignXML", "UpdSignXML\Up
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdPublish", "UpdPublish\UpdPublish.vcxproj", "{C5829278-D55E-41EB-B866-1E7D814694D1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Updater\build\Updater.vcxproj", "{990D8CF9-4457-4DC0-AA18-4968EF434741}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
@ -56,11 +53,20 @@ Global
|
||||
{C5829278-D55E-41EB-B866-1E7D814694D1}.Release|Win32.Build.0 = Release|Win32
|
||||
{C5829278-D55E-41EB-B866-1E7D814694D1}.Release|x64.ActiveCfg = Release|x64
|
||||
{C5829278-D55E-41EB-B866-1E7D814694D1}.Release|x64.Build.0 = Release|x64
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Debug|x64.Build.0 = Debug|x64
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Release|Win32.Build.0 = Release|Win32
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Release|x64.ActiveCfg = Release|x64
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{A3A36689-AC35-4026-93DA-A3BA0C0E767C} = {A7D28E0C-BB96-444D-AAB0-F22A6483FE5F}
|
||||
{990D8CF9-4457-4DC0-AA18-4968EF434741} = {A7D28E0C-BB96-444D-AAB0-F22A6483FE5F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
9
Updater/MSIBuild/.gitignore
vendored
Normal file
9
Updater/MSIBuild/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/*-1.idt
|
||||
/*-2.idt
|
||||
/*-2.idtx
|
||||
/*.Binary-1
|
||||
/*.Binary-2
|
||||
/*.Icon-1
|
||||
/*.Icon-2
|
||||
/*.lst
|
||||
/*.msm
|
106
Updater/MSIBuild/Makefile
Normal file
106
Updater/MSIBuild/Makefile
Normal file
@ -0,0 +1,106 @@
|
||||
#
|
||||
# Copyright 1991-2016 Amebis
|
||||
#
|
||||
# This file is part of ZRCola.
|
||||
#
|
||||
# ZRCola is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ZRCola is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with ZRCola. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
!INCLUDE "..\..\..\include\MSIBuildCfg.mak"
|
||||
|
||||
!IFNDEF UPDATER_BIN_DIR
|
||||
!ERROR Parameter UPDATER_BIN_DIR is undefined.
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF UPDATER_LOC_DIR
|
||||
!ERROR Parameter UPDATER_LOC_DIR is undefined.
|
||||
!ENDIF
|
||||
|
||||
|
||||
######################################################################
|
||||
# Component
|
||||
|
||||
All :: "$(LANG).$(PLAT).$(CFG).Component-1.idt"
|
||||
|
||||
"$(LANG).$(PLAT).$(CFG).Component-1.idt" : "Makefile" "..\..\..\include\MSIBuildCfg.mak"
|
||||
-if exist $@ del /f /q $@
|
||||
move /y << $@ > NUL
|
||||
Component ComponentId Directory_ Attributes Condition KeyPath
|
||||
s$(MSIBUILD_LENGTH_ID) S38 s$(MSIBUILD_LENGTH_ID) i2 S255 S$(MSIBUILD_LENGTH_ID)
|
||||
Component Component
|
||||
!IF "$(PLAT)" == "Win32"
|
||||
compUpdater.dll.Win32 {F4962976-71C3-4200-B736-BC841FEE29C2} $(UPDATER_BIN_DIR) 0 fileUpdater.dll.Win32
|
||||
!ENDIF
|
||||
!IF "$(PLAT)" == "x64"
|
||||
compUpdater.dll.x64 {A968C387-EC14-4CAC-8406-F21C9779D3EF} $(UPDATER_BIN_DIR) 256 fileUpdater.dll.x64
|
||||
!ENDIF
|
||||
!IF "$(LANG)" == "Sl"
|
||||
compUpdater.mo.sl_SI {2A56FA39-F4E6-492F-A863-AFE9E53FA988} UPDATERLOCSLSIDIR $(MSIBUILD_COMPONENT_ATTRIB_FILE) fileUpdater.mo.sl_SI
|
||||
!ENDIF
|
||||
<<NOKEEP
|
||||
|
||||
|
||||
######################################################################
|
||||
# Directory
|
||||
|
||||
All :: "$(LANG).$(PLAT).$(CFG).Directory-1.idt"
|
||||
|
||||
"$(LANG).$(PLAT).$(CFG).Directory-1.idt" : "Makefile" "..\..\..\include\MSIBuildCfg.mak"
|
||||
-if exist $@ del /f /q $@
|
||||
move /y << $@ > NUL
|
||||
Directory Directory_Parent DefaultDir
|
||||
s$(MSIBUILD_LENGTH_ID) S$(MSIBUILD_LENGTH_ID) l255
|
||||
Directory Directory
|
||||
UPDATERLOCSLSIDIR $(UPDATER_LOC_DIR) sl_SI
|
||||
<<NOKEEP
|
||||
|
||||
|
||||
######################################################################
|
||||
# File
|
||||
|
||||
All :: "$(LANG).$(PLAT).$(CFG).File-1.idt"
|
||||
|
||||
"$(LANG).$(PLAT).$(CFG).File-1.idt" : "Makefile" "..\..\..\include\MSIBuildCfg.mak"
|
||||
-if exist $@ del /f /q $@
|
||||
move /y << $@ > NUL
|
||||
File Component_ FileName FileSize Version Language Attributes Sequence
|
||||
s$(MSIBUILD_LENGTH_ID) s$(MSIBUILD_LENGTH_ID) l255 i4 S$(MSIBUILD_LENGTH_ID) S20 I2 i2
|
||||
File File
|
||||
!IF "$(PLAT)" == "Win32"
|
||||
!IF "$(CFG)" == "Release"
|
||||
fileUpdater.dll.Win32 compUpdater.dll.Win32 UPDATE~2.DLL|Updater10u_vc100.dll 0 0 1536 1
|
||||
!ENDIF
|
||||
!IF "$(CFG)" == "Debug"
|
||||
fileUpdater.dll.Win32 compUpdater.dll.Win32 UPDATE~4.DLL|Updater10ud_vc100.dll 0 0 1536 1
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
!IF "$(PLAT)" == "x64"
|
||||
!IF "$(CFG)" == "Release"
|
||||
fileUpdater.dll.x64 compUpdater.dll.x64 UPDATE~6.DLL|Updater10u_vc100_x64.dll 0 0 1536 1
|
||||
!ENDIF
|
||||
!IF "$(CFG)" == "Debug"
|
||||
fileUpdater.dll.x64 compUpdater.dll.x64 UPDATE~8.DLL|Updater10ud_vc100_x64.dll 0 0 1536 1
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
!IF "$(LANG)" == "Sl"
|
||||
fileUpdater.mo.sl_SI compUpdater.mo.sl_SI UPDATE~1.MO|Updater10.mo 0 1060 0 1
|
||||
!ENDIF
|
||||
<<NOKEEP
|
||||
|
||||
|
||||
######################################################################
|
||||
# Build MSM module!
|
||||
######################################################################
|
||||
|
||||
!INCLUDE "..\..\..\MSI\MSIBuild\MSM.mak"
|
24
Updater/build/Updater.props
Normal file
24
Updater/build/Updater.props
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<UpdaterVersion>10</UpdaterVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\output\$(Platform).$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>UPDATER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\..\lib\wxExtend\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<POCompile>
|
||||
<OutputFile>$(OutDir)..\locale\%(Filename)\$(ProjectName)$(UpdaterVersion).mo</OutputFile>
|
||||
</POCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<BuildMacro Include="UpdaterVersion">
|
||||
<Value>$(UpdaterVersion)</Value>
|
||||
</BuildMacro>
|
||||
</ItemGroup>
|
||||
</Project>
|
124
Updater/build/Updater.vcxproj
Normal file
124
Updater/build/Updater.vcxproj
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\main.cpp" />
|
||||
<ClCompile Include="..\src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\chkthread.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\include\updater\chkthread.h" />
|
||||
<ClInclude Include="..\include\Updater\common.h" />
|
||||
<ClInclude Include="..\src\stdafx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<POCompile Include="..\locale\de_DE.po" />
|
||||
<POCompile Include="..\locale\ru_RU.po" />
|
||||
<POCompile Include="..\locale\sl_SI.po" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\locale\Updater.pot" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\res\Updater.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\lib\wxExtend\build\wxExtend.vcxproj">
|
||||
<Project>{a3a36689-ac35-4026-93da-a3ba0c0e767c}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{990D8CF9-4457-4DC0-AA18-4968EF434741}</ProjectGuid>
|
||||
<RootNamespace>Updater</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\include\Win32.props" />
|
||||
<Import Project="..\..\..\include\Debug.props" />
|
||||
<Import Project="Updater.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\include\x64.props" />
|
||||
<Import Project="..\..\..\include\Debug.props" />
|
||||
<Import Project="Updater.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\include\Win32.props" />
|
||||
<Import Project="..\..\..\include\Release.props" />
|
||||
<Import Project="Updater.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\include\x64.props" />
|
||||
<Import Project="..\..\..\include\Release.props" />
|
||||
<Import Project="Updater.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetName>$(ProjectName)$(UpdaterVersion)ud_vc$(PlatformToolsetVersion)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetName>$(ProjectName)$(UpdaterVersion)ud_vc$(PlatformToolsetVersion)_$(Platform)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetName>$(ProjectName)$(UpdaterVersion)u_vc$(PlatformToolsetVersion)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetName>$(ProjectName)$(UpdaterVersion)u_vc$(PlatformToolsetVersion)_$(Platform)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\include\xgettext.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
64
Updater/build/Updater.vcxproj.filters
Normal file
64
Updater/build/Updater.vcxproj.filters
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files\Localization">
|
||||
<UniqueIdentifier>{e43059ae-37ac-4b28-84fb-18d1b3972b30}</UniqueIdentifier>
|
||||
<Extensions>po;pot</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\chkthread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\Updater\common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\updater\chkthread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\locale\Updater.pot">
|
||||
<Filter>Resource Files\Localization</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<POCompile Include="..\locale\sl_SI.po">
|
||||
<Filter>Resource Files\Localization</Filter>
|
||||
</POCompile>
|
||||
<POCompile Include="..\locale\de_DE.po">
|
||||
<Filter>Resource Files\Localization</Filter>
|
||||
</POCompile>
|
||||
<POCompile Include="..\locale\ru_RU.po">
|
||||
<Filter>Resource Files\Localization</Filter>
|
||||
</POCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\res\Updater.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
153
Updater/include/Updater/chkthread.h
Normal file
153
Updater/include/Updater/chkthread.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
Copyright 2016 Amebis
|
||||
|
||||
This file is part of Updater.
|
||||
|
||||
Updater is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Updater is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Updater. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/config.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/thread.h>
|
||||
#include <wx/xml/xml.h>
|
||||
|
||||
#include <wxex/crypto.h>
|
||||
|
||||
|
||||
///
|
||||
/// wxEVT_UPDATER_CHECK_COMPLETE event
|
||||
///
|
||||
wxDECLARE_EXPORTED_EVENT(UPDATER_API, wxEVT_UPDATER_CHECK_COMPLETE, wxThreadEvent);
|
||||
|
||||
|
||||
///
|
||||
/// Update check thread
|
||||
///
|
||||
class UPDATER_API wxUpdCheckThread : public wxThread
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Thread exit codes
|
||||
///
|
||||
enum wxResult {
|
||||
wxUpdUninitialized = -1, ///< Initialization failed
|
||||
wxUpdAborted = -2, ///< Thread aborted
|
||||
wxUpdRepoUnavailable = -3, ///< No update package information available
|
||||
wxUpdPkgUnavailable = -4, ///< Update package not available
|
||||
|
||||
wxUpdUpdateAvailable = 0, ///< Update downloaded, verified and prepared to install
|
||||
wxUpdUpToDate, ///< Product is up-to-date
|
||||
};
|
||||
|
||||
wxUpdCheckThread(const wxString &langId, wxEvtHandler *parent = NULL);
|
||||
virtual ~wxUpdCheckThread();
|
||||
|
||||
///
|
||||
/// Checks for updates and safely downloads update package when available.
|
||||
///
|
||||
inline wxResult CheckForUpdate()
|
||||
{
|
||||
return DoCheckForUpdate();
|
||||
}
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Thread's body
|
||||
///
|
||||
/// \returns Exit code
|
||||
///
|
||||
virtual ExitCode Entry();
|
||||
|
||||
///
|
||||
/// Checks for updates and safely downloads update package when available.
|
||||
///
|
||||
wxResult DoCheckForUpdate();
|
||||
|
||||
///
|
||||
/// Downloads repository database (with integrity check).
|
||||
///
|
||||
/// \returns Repository database. Use wxDELETE after use.
|
||||
///
|
||||
wxXmlDocument* GetCatalogue();
|
||||
|
||||
///
|
||||
/// Parses repository database.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if parsing succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool ParseCatalogue(const wxXmlDocument &doc);
|
||||
|
||||
///
|
||||
/// Stores update package meta-information to cache.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if writing succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool WriteUpdatePackageMeta();
|
||||
|
||||
///
|
||||
/// Retrieves update package meta-information from cache.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if reading succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool ReadUpdatePackageMeta();
|
||||
|
||||
///
|
||||
/// Downloads update package.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if downloading succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool DownloadUpdatePackage();
|
||||
|
||||
public:
|
||||
///
|
||||
/// Launches update.
|
||||
///
|
||||
/// \returns
|
||||
/// - true if launch succeeded
|
||||
/// - false otherwise
|
||||
///
|
||||
bool LaunchUpdate();
|
||||
|
||||
|
||||
protected:
|
||||
wxEvtHandler *m_parent; ///< Parent to notify
|
||||
bool m_ok; ///< Is class initialized correctly?
|
||||
|
||||
wxString m_langId; ///< Language identifier
|
||||
wxConfig m_config; ///< Application configuration
|
||||
wxString m_path; ///< Working directory (downloaded files, etc.)
|
||||
wxCryptoSession *m_cs; ///< Cryptographics session
|
||||
wxCryptoKey *m_ck; ///< Public key for update database integrity validation
|
||||
|
||||
wxUint32 m_version; ///< Latest product version available (numerical)
|
||||
wxString m_versionStr; ///< Latest product version available (string)
|
||||
wxArrayString m_urls; ///< List of update package file downloads
|
||||
wxMemoryBuffer m_hash; ///< Update package SHA-1 hash
|
||||
|
||||
wxString m_fileName; ///< Downloaded package file name
|
||||
};
|
@ -17,7 +17,11 @@
|
||||
along with Updater. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#if !defined(__UPDATER_common_h__)
|
||||
#define __UPDATER_common_h__
|
||||
|
||||
#include "../../../../include/UpdaterCfg.h"
|
||||
|
||||
|
||||
//
|
||||
// Product version as a single DWORD
|
||||
@ -42,9 +46,28 @@
|
||||
#define UPDATER_VERSION_STR "1.0"
|
||||
#define UPDATER_BUILD_YEAR_STR "2016"
|
||||
|
||||
//
|
||||
// Updater API level
|
||||
//
|
||||
#define wxUpdaterVersion "10"
|
||||
|
||||
//
|
||||
// Resource IDs
|
||||
//
|
||||
#define UPDATER_IDR_KEY_PUBLIC 1
|
||||
|
||||
#if !defined(RC_INVOKED) && !defined(MIDL_PASS)
|
||||
|
||||
///
|
||||
/// Public function calling convention
|
||||
///
|
||||
#ifdef UPDATER
|
||||
#define UPDATER_API __declspec(dllexport)
|
||||
#else
|
||||
#define UPDATER_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#define UPDATER_SIGNATURE_MARK "SHA1SIGN:"
|
||||
|
||||
#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS)
|
||||
#endif // !defined(__UPDATER_common_h__)
|
1
Updater/locale/.gitignore
vendored
Normal file
1
Updater/locale/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/*.mo
|
121
Updater/locale/Updater.pot
Normal file
121
Updater/locale/Updater.pot
Normal file
@ -0,0 +1,121 @@
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Updater\n"
|
||||
"POT-Creation-Date: 2016-05-24 15:34+0200\n"
|
||||
"PO-Revision-Date: 2016-02-06 09:04+0100\n"
|
||||
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
|
||||
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
|
||||
"Language: en\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.7\n"
|
||||
"X-Poedit-Basepath: ..\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: _\n"
|
||||
"X-Poedit-SearchPath-0: src\n"
|
||||
"X-Poedit-SearchPath-1: include\n"
|
||||
|
||||
#: src/chkthread.cpp:79 src/chkthread.cpp:92
|
||||
msgid "Update check complete. Your product is up to date."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:112
|
||||
msgid "Downloading repository catalogue..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:120
|
||||
#, c-format
|
||||
msgid "Contacting repository at %s..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:128
|
||||
#, c-format
|
||||
msgid "Error resolving %s server name."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:133
|
||||
msgid "Repository did not change since the last time."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:137
|
||||
#, c-format
|
||||
msgid "Error response received from server %s (port %u) requesting %s."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:145
|
||||
msgid "Error loading repository catalogue."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:155
|
||||
msgid "Verifying repository catalogue signature..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:186
|
||||
msgid "Signature not found in the repository catalogue."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:208
|
||||
msgid "Repository catalogue signature does not match its content, or signature verification failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:216
|
||||
#, c-format
|
||||
msgid "Invalid root element in repository catalogue (actual: %s, expected: %s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:234
|
||||
msgid "Parsing repository catalogue..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:319
|
||||
#, c-format
|
||||
msgid "Update package found (version: %s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:377
|
||||
msgid "Reading update package meta-information from cache failed or incomplete."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:399
|
||||
msgid "Update package file already downloaded."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:406
|
||||
#, c-format
|
||||
msgid "Can not open/create %s file for writing."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:426
|
||||
#, c-format
|
||||
msgid "Downloading update package from %s..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:429
|
||||
msgid "Error response received."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:448
|
||||
#, c-format
|
||||
msgid "Can not write to %s file."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:462
|
||||
msgid "Update package file corrupt."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:471
|
||||
msgid "Launching update..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:491
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch succeeded. For further information, see %s file."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:494
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch failed. ShellExecute returned %i."
|
||||
msgstr ""
|
122
Updater/locale/de_DE.po
Normal file
122
Updater/locale/de_DE.po
Normal file
@ -0,0 +1,122 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Updater\n"
|
||||
"POT-Creation-Date: 2016-05-24 15:35+0200\n"
|
||||
"PO-Revision-Date: 2016-05-24 15:35+0200\n"
|
||||
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
|
||||
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.7\n"
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: _\n"
|
||||
|
||||
#: src/chkthread.cpp:79 src/chkthread.cpp:92
|
||||
msgid "Update check complete. Your product is up to date."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:112
|
||||
msgid "Downloading repository catalogue..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:120
|
||||
#, c-format
|
||||
msgid "Contacting repository at %s..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:128
|
||||
#, c-format
|
||||
msgid "Error resolving %s server name."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:133
|
||||
msgid "Repository did not change since the last time."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:137
|
||||
#, c-format
|
||||
msgid "Error response received from server %s (port %u) requesting %s."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:145
|
||||
msgid "Error loading repository catalogue."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:155
|
||||
msgid "Verifying repository catalogue signature..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:186
|
||||
msgid "Signature not found in the repository catalogue."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:208
|
||||
msgid ""
|
||||
"Repository catalogue signature does not match its content, or signature "
|
||||
"verification failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:216
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Invalid root element in repository catalogue (actual: %s, expected: %s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:234
|
||||
msgid "Parsing repository catalogue..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:319
|
||||
#, c-format
|
||||
msgid "Update package found (version: %s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:377
|
||||
msgid ""
|
||||
"Reading update package meta-information from cache failed or incomplete."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:399
|
||||
msgid "Update package file already downloaded."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:406
|
||||
#, c-format
|
||||
msgid "Can not open/create %s file for writing."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:426
|
||||
#, c-format
|
||||
msgid "Downloading update package from %s..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:429
|
||||
msgid "Error response received."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:448
|
||||
#, c-format
|
||||
msgid "Can not write to %s file."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:462
|
||||
msgid "Update package file corrupt."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:471
|
||||
msgid "Launching update..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:491
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch succeeded. For further information, see %s file."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:494
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch failed. ShellExecute returned %i."
|
||||
msgstr ""
|
123
Updater/locale/ru_RU.po
Normal file
123
Updater/locale/ru_RU.po
Normal file
@ -0,0 +1,123 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Updater\n"
|
||||
"POT-Creation-Date: 2016-05-24 15:35+0200\n"
|
||||
"PO-Revision-Date: 2016-05-24 15:35+0200\n"
|
||||
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
|
||||
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
|
||||
"Language: ru_RU\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.7\n"
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: _\n"
|
||||
|
||||
#: src/chkthread.cpp:79 src/chkthread.cpp:92
|
||||
msgid "Update check complete. Your product is up to date."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:112
|
||||
msgid "Downloading repository catalogue..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:120
|
||||
#, c-format
|
||||
msgid "Contacting repository at %s..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:128
|
||||
#, c-format
|
||||
msgid "Error resolving %s server name."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:133
|
||||
msgid "Repository did not change since the last time."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:137
|
||||
#, c-format
|
||||
msgid "Error response received from server %s (port %u) requesting %s."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:145
|
||||
msgid "Error loading repository catalogue."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:155
|
||||
msgid "Verifying repository catalogue signature..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:186
|
||||
msgid "Signature not found in the repository catalogue."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:208
|
||||
msgid ""
|
||||
"Repository catalogue signature does not match its content, or signature "
|
||||
"verification failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:216
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Invalid root element in repository catalogue (actual: %s, expected: %s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:234
|
||||
msgid "Parsing repository catalogue..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:319
|
||||
#, c-format
|
||||
msgid "Update package found (version: %s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:377
|
||||
msgid ""
|
||||
"Reading update package meta-information from cache failed or incomplete."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:399
|
||||
msgid "Update package file already downloaded."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:406
|
||||
#, c-format
|
||||
msgid "Can not open/create %s file for writing."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:426
|
||||
#, c-format
|
||||
msgid "Downloading update package from %s..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:429
|
||||
msgid "Error response received."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:448
|
||||
#, c-format
|
||||
msgid "Can not write to %s file."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:462
|
||||
msgid "Update package file corrupt."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:471
|
||||
msgid "Launching update..."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:491
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch succeeded. For further information, see %s file."
|
||||
msgstr ""
|
||||
|
||||
#: src/chkthread.cpp:494
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch failed. ShellExecute returned %i."
|
||||
msgstr ""
|
130
Updater/locale/sl_SI.po
Normal file
130
Updater/locale/sl_SI.po
Normal file
@ -0,0 +1,130 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Updater\n"
|
||||
"POT-Creation-Date: 2016-05-24 15:34+0200\n"
|
||||
"PO-Revision-Date: 2016-05-24 15:35+0200\n"
|
||||
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
|
||||
"Language-Team: Amebis, d. o. o., Kamnik <info@amebis.si>\n"
|
||||
"Language: sl_SI\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.7\n"
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n"
|
||||
"%100==4 ? 2 : 3);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: _\n"
|
||||
|
||||
#: src/chkthread.cpp:79 src/chkthread.cpp:92
|
||||
msgid "Update check complete. Your product is up to date."
|
||||
msgstr "Preverjanje posodobitev končano. Vaš izdelek je zadnje verzije."
|
||||
|
||||
#: src/chkthread.cpp:112
|
||||
msgid "Downloading repository catalogue..."
|
||||
msgstr "Prenos repozitorijevega kataloga ..."
|
||||
|
||||
#: src/chkthread.cpp:120
|
||||
#, c-format
|
||||
msgid "Contacting repository at %s..."
|
||||
msgstr "Dostop do repozitorija na %s ..."
|
||||
|
||||
#: src/chkthread.cpp:128
|
||||
#, c-format
|
||||
msgid "Error resolving %s server name."
|
||||
msgstr "Napaka pri ugotavljanju naslova strežnika %s."
|
||||
|
||||
#: src/chkthread.cpp:133
|
||||
msgid "Repository did not change since the last time."
|
||||
msgstr "Repozitorij se od zadnjič ni spremenil."
|
||||
|
||||
#: src/chkthread.cpp:137
|
||||
#, c-format
|
||||
msgid "Error response received from server %s (port %u) requesting %s."
|
||||
msgstr "Prejet odgovor o napaki s strežnika %s (vrata %u) pri zahtevi za %s."
|
||||
|
||||
#: src/chkthread.cpp:145
|
||||
msgid "Error loading repository catalogue."
|
||||
msgstr "Napaka pri nalaganju repozitorijevega kataloga."
|
||||
|
||||
#: src/chkthread.cpp:155
|
||||
msgid "Verifying repository catalogue signature..."
|
||||
msgstr "Preverjanje podpisa repozitorijevega kataloga ..."
|
||||
|
||||
#: src/chkthread.cpp:186
|
||||
msgid "Signature not found in the repository catalogue."
|
||||
msgstr "V repozitorijevem katalogu ni podpisa."
|
||||
|
||||
#: src/chkthread.cpp:208
|
||||
msgid ""
|
||||
"Repository catalogue signature does not match its content, or signature "
|
||||
"verification failed."
|
||||
msgstr ""
|
||||
"Podpis repozitorijevega kataloga ne ustreza njegovi vsebini, oziroma "
|
||||
"preverjanje podpisa ni uspelo."
|
||||
|
||||
#: src/chkthread.cpp:216
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Invalid root element in repository catalogue (actual: %s, expected: %s)."
|
||||
msgstr ""
|
||||
"Napačen korenski element v repozitorijevem katalogu (dejanski: %s, "
|
||||
"pričakovan: %s)."
|
||||
|
||||
#: src/chkthread.cpp:234
|
||||
msgid "Parsing repository catalogue..."
|
||||
msgstr "Razčlemba repozitorijevega kataloga ..."
|
||||
|
||||
#: src/chkthread.cpp:319
|
||||
#, c-format
|
||||
msgid "Update package found (version: %s)."
|
||||
msgstr "Posodobitveni paket najden (verzija: %s)."
|
||||
|
||||
#: src/chkthread.cpp:377
|
||||
msgid ""
|
||||
"Reading update package meta-information from cache failed or incomplete."
|
||||
msgstr ""
|
||||
"Branje meta-informacij posodobitvenega paketa iz predpomnilnika ni uspelo "
|
||||
"ali ni bilo celotno."
|
||||
|
||||
#: src/chkthread.cpp:399
|
||||
msgid "Update package file already downloaded."
|
||||
msgstr "Posodobitveni paket je že prenesen."
|
||||
|
||||
#: src/chkthread.cpp:406
|
||||
#, c-format
|
||||
msgid "Can not open/create %s file for writing."
|
||||
msgstr "Ne morem odpreti/ustvariti datoteke %s za pisanje."
|
||||
|
||||
#: src/chkthread.cpp:426
|
||||
#, c-format
|
||||
msgid "Downloading update package from %s..."
|
||||
msgstr "Prenos posodobitvenega paketa s/z %s ..."
|
||||
|
||||
#: src/chkthread.cpp:429
|
||||
msgid "Error response received."
|
||||
msgstr "Prejet odgovor o napaki."
|
||||
|
||||
#: src/chkthread.cpp:448
|
||||
#, c-format
|
||||
msgid "Can not write to %s file."
|
||||
msgstr "Ne morem pisati v datoteko %s."
|
||||
|
||||
#: src/chkthread.cpp:462
|
||||
msgid "Update package file corrupt."
|
||||
msgstr "Posodobitveni paket je pokvarjen."
|
||||
|
||||
#: src/chkthread.cpp:471
|
||||
msgid "Launching update..."
|
||||
msgstr "Zagon posodobitve ..."
|
||||
|
||||
#: src/chkthread.cpp:491
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch succeeded. For further information, see %s file."
|
||||
msgstr ""
|
||||
"Zagon msiexec.exe je uspel. Za nadaljnje informacije glejte datoteko %s."
|
||||
|
||||
#: src/chkthread.cpp:494
|
||||
#, c-format
|
||||
msgid "msiexec.exe launch failed. ShellExecute returned %i."
|
||||
msgstr "Zagon msiexec.exe ni uspel. ShellExecute je vrnil %i."
|
BIN
Updater/res/Updater.rc
Normal file
BIN
Updater/res/Updater.rc
Normal file
Binary file not shown.
518
Updater/src/chkthread.cpp
Normal file
518
Updater/src/chkthread.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
/*
|
||||
Copyright 2016 Amebis
|
||||
|
||||
This file is part of Updater.
|
||||
|
||||
Updater is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Updater is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Updater. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_UPDATER_CHECK_COMPLETE, wxThreadEvent);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// wxUpdCheckThread
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
wxUpdCheckThread::wxUpdCheckThread(const wxString &langId, wxEvtHandler *parent) :
|
||||
m_parent(parent),
|
||||
m_langId(langId),
|
||||
m_config(wxT(UPDATER_CFG_APPLICATION) wxT("\\Updater"), wxT(UPDATER_CFG_VENDOR)),
|
||||
m_cs(NULL),
|
||||
m_ck(NULL),
|
||||
m_version(0),
|
||||
wxThread(wxTHREAD_JOINABLE)
|
||||
{
|
||||
m_path = wxFileName::GetTempDir();
|
||||
if (!wxEndsWithPathSeparator(m_path))
|
||||
m_path += wxFILE_SEP_PATH;
|
||||
|
||||
if (!wxDirExists(m_path))
|
||||
wxMkdir(m_path);
|
||||
|
||||
m_cs = new wxCryptoSessionRSAAES();
|
||||
wxCHECK2_MSG(m_cs, { m_ok = false; return; }, wxT("wxCryptoSessionRSAAES creation failed"));
|
||||
|
||||
// Import public key.
|
||||
HRSRC res = ::FindResource(g_hInstance, MAKEINTRESOURCE(UPDATER_IDR_KEY_PUBLIC), RT_RCDATA);
|
||||
wxCHECK2_MSG(res, { m_ok = false; return; }, wxT("public key not found"));
|
||||
HGLOBAL res_handle = ::LoadResource(g_hInstance, res);
|
||||
wxCHECK2_MSG(res_handle, { m_ok = false; return; }, wxT("loading resource failed"));
|
||||
|
||||
m_ck = new wxCryptoKey();
|
||||
wxCHECK2_MSG(m_ck, { m_ok = false; return; }, wxT("wxCryptoKey creation failed"));
|
||||
wxCHECK2(m_ck->ImportPublic(*m_cs, ::LockResource(res_handle), ::SizeofResource(g_hInstance, res)), { m_ok = false; return; });
|
||||
}
|
||||
|
||||
|
||||
wxUpdCheckThread::~wxUpdCheckThread()
|
||||
{
|
||||
if (m_ck) delete m_ck;
|
||||
if (m_cs) delete m_cs;
|
||||
}
|
||||
|
||||
|
||||
wxThread::ExitCode wxUpdCheckThread::Entry()
|
||||
{
|
||||
wxResult result = DoCheckForUpdate();
|
||||
|
||||
if (m_parent) {
|
||||
// Signal the event handler that this thread is going to be destroyed.
|
||||
// NOTE: here we assume that using the m_parent pointer is safe,
|
||||
// (in this case this is assured by the wxZRColaCharSelect destructor)
|
||||
wxThreadEvent *e = new wxThreadEvent(wxEVT_UPDATER_CHECK_COMPLETE);
|
||||
e->SetInt(result);
|
||||
wxQueueEvent(m_parent, e);
|
||||
}
|
||||
|
||||
return (wxThread::ExitCode)(int)result;
|
||||
}
|
||||
|
||||
|
||||
wxUpdCheckThread::wxResult wxUpdCheckThread::DoCheckForUpdate()
|
||||
{
|
||||
if (!m_ok)
|
||||
return wxUpdUninitialized;
|
||||
|
||||
// Download update catalogue.
|
||||
if (TestDestroy()) return wxUpdAborted;
|
||||
wxXmlDocument *doc = GetCatalogue();
|
||||
if (doc) {
|
||||
// Parse the update catalogue to check for an update package availability.
|
||||
if (TestDestroy()) return wxUpdAborted;
|
||||
if (ParseCatalogue(*doc)) {
|
||||
// Save update package meta-information for the next time.
|
||||
if (TestDestroy()) return wxUpdAborted;
|
||||
WriteUpdatePackageMeta();
|
||||
} else {
|
||||
wxLogStatus(_("Update check complete. Your product is up to date."));
|
||||
return wxUpdUpToDate;
|
||||
}
|
||||
} else {
|
||||
// Update download catalogue failed, or repository database didn't change. Read a cached version of update package meta-information?
|
||||
if (TestDestroy()) return wxUpdAborted;
|
||||
if (!ReadUpdatePackageMeta()) {
|
||||
// Reset CatalogueLastModified to force update catalogue download next time.
|
||||
m_config.DeleteEntry(wxT("CatalogueLastModified"));
|
||||
return wxUpdRepoUnavailable;
|
||||
}
|
||||
|
||||
if (m_version <= UPDATER_PRODUCT_VERSION) {
|
||||
wxLogStatus(_("Update check complete. Your product is up to date."));
|
||||
return wxUpdUpToDate;
|
||||
}
|
||||
}
|
||||
|
||||
m_fileName = m_path;
|
||||
m_fileName += wxT("Updater-") wxT(UPDATER_CFG_APPLICATION) wxT("-");
|
||||
m_fileName += m_versionStr;
|
||||
m_fileName += wxT(".msi");
|
||||
|
||||
if (TestDestroy()) return wxUpdAborted;
|
||||
if (!DownloadUpdatePackage())
|
||||
return wxUpdPkgUnavailable;
|
||||
|
||||
return wxUpdUpdateAvailable;
|
||||
}
|
||||
|
||||
|
||||
wxXmlDocument* wxUpdCheckThread::GetCatalogue()
|
||||
{
|
||||
wxLogStatus(_("Downloading repository catalogue..."));
|
||||
|
||||
wxString lastModified;
|
||||
m_config.Read(wxT("CatalogueLastModified"), &lastModified, wxEmptyString);
|
||||
|
||||
for (const wxChar *server = wxT(UPDATER_HTTP_SERVER); server[0]; server += wcslen(server) + 1) {
|
||||
if (TestDestroy()) return NULL;
|
||||
|
||||
wxLogStatus(_("Contacting repository at %s..."), server);
|
||||
|
||||
// Load repository database.
|
||||
wxHTTP http;
|
||||
http.SetHeader(wxS("User-Agent"), wxS("Updater/") wxS(UPDATER_VERSION_STR));
|
||||
if (!lastModified.IsEmpty())
|
||||
http.SetHeader(wxS("If-Modified-Since"), lastModified);
|
||||
if (!http.Connect(server, UPDATER_HTTP_PORT)) {
|
||||
wxLogWarning(_("Error resolving %s server name."), server);
|
||||
continue;
|
||||
}
|
||||
wxInputStream *httpStream = http.GetInputStream(wxS(UPDATER_HTTP_PATH));
|
||||
if (http.GetResponse() == 304) {
|
||||
wxLogStatus(_("Repository did not change since the last time."));
|
||||
wxDELETE(httpStream);
|
||||
return NULL;
|
||||
} else if (!httpStream) {
|
||||
wxLogWarning(_("Error response received from server %s (port %u) requesting %s."), server, UPDATER_HTTP_PORT, UPDATER_HTTP_PATH);
|
||||
continue;
|
||||
} else if (TestDestroy()) {
|
||||
wxDELETE(httpStream);
|
||||
return NULL;
|
||||
}
|
||||
wxXmlDocument *doc = new wxXmlDocument();
|
||||
if (!doc->Load(*httpStream, "UTF-8", wxXMLDOC_KEEP_WHITESPACE_NODES)) {
|
||||
wxLogWarning(_("Error loading repository catalogue."));
|
||||
wxDELETE(httpStream);
|
||||
http.Close();
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
wxDELETE(httpStream);
|
||||
m_config.Write(wxT("CatalogueLastModified"), http.GetHeader(wxT("Last-Modified")));
|
||||
http.Close();
|
||||
|
||||
wxLogStatus(_("Verifying repository catalogue signature..."));
|
||||
|
||||
// Find the (first) signature.
|
||||
if (TestDestroy()) return NULL;
|
||||
wxXmlNode *document = doc->GetDocumentNode();
|
||||
wxMemoryBuffer sig;
|
||||
for (wxXmlNode *prolog = document->GetChildren(); prolog; prolog = prolog->GetNext()) {
|
||||
if (prolog->GetType() == wxXML_COMMENT_NODE) {
|
||||
wxString content = prolog->GetContent();
|
||||
size_t content_len = content.length();
|
||||
if (content_len >= _countof(wxS(UPDATER_SIGNATURE_MARK)) - 1 &&
|
||||
memcmp((const wxStringCharType*)content, wxS(UPDATER_SIGNATURE_MARK), sizeof(wxStringCharType)*(_countof(wxS(UPDATER_SIGNATURE_MARK)) - 1)) == 0)
|
||||
{
|
||||
// Read the signature.
|
||||
size_t signature_len = content_len - (_countof(wxS(UPDATER_SIGNATURE_MARK)) - 1);
|
||||
size_t len = wxBase64DecodedSize(signature_len);
|
||||
size_t res = wxBase64Decode(sig.GetWriteBuf(len), len, content.Right(signature_len), wxBase64DecodeMode_SkipWS);
|
||||
if (res != wxCONV_FAILED) {
|
||||
sig.SetDataLen(res);
|
||||
|
||||
// Remove the signature as it is not a part of the validation check.
|
||||
document->RemoveChild(prolog);
|
||||
wxDELETE(prolog);
|
||||
break;
|
||||
} else
|
||||
sig.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sig.IsEmpty()) {
|
||||
wxLogWarning(_("Signature not found in the repository catalogue."));
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hash the content.
|
||||
if (TestDestroy()) {
|
||||
delete doc;
|
||||
return NULL;
|
||||
}
|
||||
wxCryptoHashSHA1 ch(*m_cs);
|
||||
if (!wxXmlHashNode(ch, document)) {
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have the hash, we have the signature, we have the public key. Now verify.
|
||||
if (TestDestroy()) {
|
||||
delete doc;
|
||||
return NULL;
|
||||
}
|
||||
if (!wxCryptoVerifySignature(ch, sig, *m_ck)) {
|
||||
wxLogWarning(_("Repository catalogue signature does not match its content, or signature verification failed."));
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify document type (root element).
|
||||
const wxString &nameRoot = doc->GetRoot()->GetName();
|
||||
if (nameRoot != wxT("Packages")) {
|
||||
wxLogWarning(_("Invalid root element in repository catalogue (actual: %s, expected: %s)."), nameRoot.c_str(), wxT("Packages"));
|
||||
delete doc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The downloaded repository database passed all checks.
|
||||
return doc;
|
||||
}
|
||||
|
||||
// No repository database downloaded successfully.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckThread::ParseCatalogue(const wxXmlDocument &doc)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
wxLogStatus(_("Parsing repository catalogue..."));
|
||||
|
||||
// Iterate over packages.
|
||||
for (wxXmlNode *elPackage = doc.GetRoot()->GetChildren(); elPackage; elPackage = elPackage->GetNext()) {
|
||||
if (TestDestroy()) return false;
|
||||
|
||||
if (elPackage->GetType() == wxXML_ELEMENT_NODE && elPackage->GetName() == wxT("Package")) {
|
||||
// Get package version.
|
||||
wxUint32 version = 0;
|
||||
wxString versionStr;
|
||||
for (wxXmlNode *elVersion = elPackage->GetChildren(); elVersion; elVersion = elVersion->GetNext()) {
|
||||
if (elVersion->GetType() == wxXML_ELEMENT_NODE && elVersion->GetName() == wxT("Version")) {
|
||||
for (wxXmlNode *elVersionNote = elVersion->GetChildren(); elVersionNote; elVersionNote = elVersionNote->GetNext()) {
|
||||
if (elVersionNote->GetType() == wxXML_ELEMENT_NODE) {
|
||||
const wxString &name = elVersionNote->GetName();
|
||||
if (name == wxT("hex"))
|
||||
version = _tcstoul(elVersionNote->GetNodeContent(), NULL, 16);
|
||||
else if (name == wxT("desc"))
|
||||
versionStr = elVersionNote->GetNodeContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version <= UPDATER_PRODUCT_VERSION || version < m_version) {
|
||||
// This package is older than currently installed product or the superseeded package found already.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get package download URL for our platform and language.
|
||||
wxString platformId;
|
||||
#if defined(__WINDOWS__)
|
||||
platformId += wxT("win");
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
platformId += wxT("-amd64");
|
||||
#else
|
||||
platformId += wxT("-x86");
|
||||
#endif
|
||||
wxArrayString urls;
|
||||
wxMemoryBuffer hash;
|
||||
for (wxXmlNode *elDownloads = elPackage->GetChildren(); elDownloads; elDownloads = elDownloads->GetNext()) {
|
||||
if (elDownloads->GetType() == wxXML_ELEMENT_NODE && elDownloads->GetName() == wxT("Downloads")) {
|
||||
for (wxXmlNode *elPlatform = elDownloads->GetChildren(); elPlatform; elPlatform = elPlatform->GetNext()) {
|
||||
if (elPlatform->GetType() == wxXML_ELEMENT_NODE) {
|
||||
if (elPlatform->GetName() == wxT("Platform") && elPlatform->GetAttribute(wxT("id")) == platformId) {
|
||||
// Get language.
|
||||
for (wxXmlNode *elLocale = elPlatform->GetChildren(); elLocale; elLocale = elLocale->GetNext()) {
|
||||
if (elLocale->GetType() == wxXML_ELEMENT_NODE && elLocale->GetName() == wxT("Localization") && elLocale->GetAttribute(wxT("lang")) == m_langId) {
|
||||
for (wxXmlNode *elLocaleNote = elLocale->GetChildren(); elLocaleNote; elLocaleNote = elLocaleNote->GetNext()) {
|
||||
if (elLocaleNote->GetType() == wxXML_ELEMENT_NODE) {
|
||||
const wxString &name = elLocaleNote->GetName();
|
||||
if (name == wxT("url"))
|
||||
urls.Add(elLocaleNote->GetNodeContent());
|
||||
else if (name == wxT("hash")) {
|
||||
// Read the hash.
|
||||
wxString content(elLocaleNote->GetNodeContent());
|
||||
size_t len = wxHexDecodedSize(content.length());
|
||||
size_t res = wxHexDecode(hash.GetWriteBuf(len), len, content, wxHexDecodeMode_SkipWS);
|
||||
if (res != wxCONV_FAILED)
|
||||
hash.SetDataLen(res);
|
||||
else
|
||||
hash.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (urls.empty() || hash.IsEmpty()) {
|
||||
// This package is for different architecture and/or language.
|
||||
// ... or missing URL and/or hash.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save found package info.
|
||||
m_version = version;
|
||||
m_versionStr = versionStr;
|
||||
m_urls = urls;
|
||||
m_hash = hash;
|
||||
found = true;
|
||||
|
||||
wxLogMessage(_("Update package found (version: %s)."), m_versionStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckThread::WriteUpdatePackageMeta()
|
||||
{
|
||||
// Concatenate URLs.
|
||||
wxString urls;
|
||||
for (size_t i = 0, n = m_urls.GetCount(); i < n; i++) {
|
||||
if (i) urls += wxT('\n');
|
||||
urls += m_urls[i];
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
if (!m_config.Write(wxT("PackageVersion" ), m_version )) result = false;
|
||||
if (!m_config.Write(wxT("PackageVersionDesc"), m_versionStr )) result = false;
|
||||
if (!m_config.Write(wxT("PackageURLs" ), urls )) result = false;
|
||||
if (!m_config.Write(wxT("PackageHash" ), wxHexEncode(m_hash))) result = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckThread::ReadUpdatePackageMeta()
|
||||
{
|
||||
long lng;
|
||||
if (m_config.Read(wxT("PackageVersion"), &lng)) {
|
||||
m_version = lng;
|
||||
if (m_config.Read(wxT("PackageVersionDesc"), &m_versionStr)) {
|
||||
wxString str;
|
||||
if (m_config.Read(wxT("PackageURLs"), &str)) {
|
||||
// Split URLs
|
||||
m_urls.Clear();
|
||||
const wxStringCharType *buf = str;
|
||||
for (size_t i = 0, j = 0, n = str.Length(); i < n;) {
|
||||
for (; j < n && buf[j] != wxT('\n'); j++);
|
||||
m_urls.Add(str.SubString(i, j - 1));
|
||||
i = ++j;
|
||||
}
|
||||
|
||||
if (m_config.Read(wxT("PackageHash"), &str)) {
|
||||
// Convert to binary.
|
||||
size_t len = wxHexDecodedSize(str.length());
|
||||
size_t res = wxHexDecode(m_hash.GetWriteBuf(len), len, str, wxHexDecodeMode_SkipWS);
|
||||
if (res != wxCONV_FAILED) {
|
||||
m_hash.SetDataLen(res);
|
||||
return true;
|
||||
} else
|
||||
m_hash.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxLogWarning(_("Reading update package meta-information from cache failed or incomplete."));
|
||||
m_version = 0;
|
||||
m_versionStr.Clear();
|
||||
m_urls.Clear();
|
||||
m_hash.Clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckThread::DownloadUpdatePackage()
|
||||
{
|
||||
// Calculate file hash (if exists).
|
||||
wxCryptoHashSHA1 ch(*m_cs);
|
||||
if (ch.HashFile(m_fileName)) {
|
||||
wxMemoryBuffer buf;
|
||||
ch.GetValue(buf);
|
||||
|
||||
if (buf.GetDataLen() == m_hash.GetDataLen() &&
|
||||
memcmp(buf.GetData(), m_hash.GetData(), buf.GetDataLen()) == 0)
|
||||
{
|
||||
// Update package file exists and its hash is correct.
|
||||
wxLogStatus(_("Update package file already downloaded."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
wxFFile file(m_fileName, wxT("wb"));
|
||||
if (!file.IsOpened()) {
|
||||
wxLogError(_("Can not open/create %s file for writing."), m_fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Download update package file.
|
||||
for (size_t i = 0, n = m_urls.GetCount(); i < n; i++) {
|
||||
if (TestDestroy()) return false;
|
||||
|
||||
wxURL url(m_urls[i]);
|
||||
if (!url.IsOk())
|
||||
continue;
|
||||
|
||||
if (url.HasScheme()) {
|
||||
const wxString scheme = url.GetScheme();
|
||||
if (scheme == wxT("http") || scheme == wxT("https")) {
|
||||
wxHTTP &http = (wxHTTP&)url.GetProtocol();
|
||||
http.SetHeader(wxS("User-Agent"), wxS("Updater/") wxS(UPDATER_VERSION_STR));
|
||||
}
|
||||
}
|
||||
|
||||
wxLogStatus(_("Downloading update package from %s..."), m_urls[i].c_str());
|
||||
wxInputStream *stream = url.GetInputStream();
|
||||
if (!stream) {
|
||||
wxLogWarning(_("Error response received."));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save update package to file, and calculate hash.
|
||||
wxCryptoHashSHA1 ch(*m_cs);
|
||||
wxMemoryBuffer buf(4*1024);
|
||||
char *data = (char*)buf.GetData();
|
||||
size_t nBlock = buf.GetBufSize();
|
||||
do {
|
||||
if (TestDestroy()) {
|
||||
wxDELETE(stream);
|
||||
return false;
|
||||
}
|
||||
|
||||
stream->Read(data, nBlock);
|
||||
size_t nRead = stream->LastRead();
|
||||
file.Write(data, nRead);
|
||||
if (file.Error()) {
|
||||
wxLogError(_("Can not write to %s file."), m_fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
ch.Hash(data, nRead);
|
||||
} while (stream->IsOk());
|
||||
ch.GetValue(buf);
|
||||
wxDELETE(stream);
|
||||
|
||||
if (buf.GetDataLen() == m_hash.GetDataLen() &&
|
||||
memcmp(buf.GetData(), m_hash.GetData(), buf.GetDataLen()) == 0)
|
||||
{
|
||||
// Update package file downloaded and its hash is correct.
|
||||
return true;
|
||||
} else
|
||||
wxLogWarning(_("Update package file corrupt."));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool wxUpdCheckThread::LaunchUpdate()
|
||||
{
|
||||
wxLogStatus(_("Launching update..."));
|
||||
|
||||
// Headless Install
|
||||
wxString param("/qn");
|
||||
|
||||
// Package
|
||||
param += wxT(" /i \"");
|
||||
param += m_fileName;
|
||||
param += wxT("\"");
|
||||
|
||||
// Logging
|
||||
wxString fileNameLog(m_path);
|
||||
fileNameLog += wxT("Updater-") wxT(UPDATER_CFG_APPLICATION) wxT("-msiexec.log");
|
||||
|
||||
param += wxT(" /l* \"");
|
||||
param += fileNameLog;
|
||||
param += wxT("\"");
|
||||
|
||||
int result = (int)::ShellExecute(NULL, NULL, wxT("msiexec.exe"), param, NULL, SW_SHOWNORMAL);
|
||||
if (result > 32) {
|
||||
wxLogStatus(_("msiexec.exe launch succeeded. For further information, see %s file."), fileNameLog.c_str());
|
||||
return true;
|
||||
} else {
|
||||
wxLogError(_("msiexec.exe launch failed. ShellExecute returned %i."), result);
|
||||
return false;
|
||||
}
|
||||
}
|
40
Updater/src/main.cpp
Normal file
40
Updater/src/main.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2016 Amebis
|
||||
|
||||
This file is part of Updater.
|
||||
|
||||
Updater is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Updater is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Updater. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
///
|
||||
/// Module instance
|
||||
///
|
||||
HINSTANCE g_hInstance = NULL;
|
||||
|
||||
|
||||
///
|
||||
/// Main function
|
||||
///
|
||||
BOOL WINAPI DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpvReserved);
|
||||
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
g_hInstance = hinstDLL;
|
||||
|
||||
return TRUE;
|
||||
}
|
20
Updater/src/stdafx.cpp
Normal file
20
Updater/src/stdafx.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2016 Amebis
|
||||
|
||||
This file is part of Updater.
|
||||
|
||||
Updater is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Updater is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Updater. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
37
Updater/src/stdafx.h
Normal file
37
Updater/src/stdafx.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2016 Amebis
|
||||
|
||||
This file is part of Updater.
|
||||
|
||||
Updater is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Updater is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Updater. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/Updater/chkthread.h"
|
||||
|
||||
#include <wx/base64.h>
|
||||
#include <wx/buffer.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/protocol/http.h>
|
||||
#include <wx/url.h>
|
||||
|
||||
#include <wxex/hex.h>
|
||||
#include <wxex/xml.h>
|
||||
|
||||
//
|
||||
// Private data declaration
|
||||
//
|
||||
extern HINSTANCE g_hInstance;
|
Loading…
x
Reference in New Issue
Block a user