View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001011 | OpenMPT | Installer and Update | public | 2017-08-14 10:24 | 2024-10-10 08:16 |
Reporter | Saga Musix | Assigned To | manx | ||
Priority | low | Severity | minor | Reproducibility | N/A |
Status | resolved | Resolution | fixed | ||
Target Version | OpenMPT 1.30.01.00 / libopenmpt 0.6.0 (upgrade first) | Fixed in Version | OpenMPT 1.30.01.00 / libopenmpt 0.6.0 (upgrade first) | ||
Summary | 0001011: Automatic update | ||||
Description | There are already automatic update notifications, but people are lazy, so in addition we should offer to show what's new and automatically install the new version. In case someone is skipping several versions, we might want to show the news for all skipped versions as well. Not the complete changelog of course, but just the most important items. We will need a differently structured response from the server, and since picojson is already used for the Wine integration, using JSON for update information seems like a good idea. The update response could look something like this:
The rationale for sending all download links to the client is that information about the user's operating system environment is sent to the server optionally. I think data avoidance is a goal worth striving for, so we should not force this information to be sent along.
What else needs to be considered:
| ||||
Tags | No tags attached. | ||||
Attached Files | update-statistics-v2.patch (34,400 bytes)
Index: common/versionNumber.h =================================================================== --- common/versionNumber.h (revision 10676) +++ common/versionNumber.h (working copy) @@ -21,7 +21,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 28 #define VER_MINOR 00 -#define VER_MINORMINOR 28 +#define VER_MINORMINOR 29 //Numerical value of the version. #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR) Index: mptrack/mptrack.rc =================================================================== --- mptrack/mptrack.rc (revision 10676) +++ mptrack/mptrack.rc (working copy) @@ -244,22 +244,25 @@ CAPTION "Update" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Check for Updates",IDC_STATIC,6,6,276,66 - CONTROL "&Never",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,12,18,240,8 - CONTROL "&Daily",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,12,30,240,8 - CONTROL "&Weekly (recommended)",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,12,42,240,8 - CONTROL "&Monthly",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,12,54,240,8 - GROUPBOX "Privacy Settings",IDC_STATIC,6,78,276,54 - CONTROL "&Allow us to collect basic update statistics",IDC_CHECK1, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,90,246,12 - LTEXT "If enabled, a randomized user ID is created and transmitted with every update check. This ID can not be linked to you or your computer in any way.",IDC_STATIC,12,102,264,24 - GROUPBOX "Advanced Settings",IDC_STATIC,6,138,276,60 - LTEXT "&Update server URL:",IDC_STATIC,12,150,186,8 - EDITTEXT IDC_EDIT1,12,162,264,12,ES_AUTOHSCROLL - PUSHBUTTON "&Reset",IDC_BUTTON2,222,146,54,12 - LTEXT "Do not change this unless you are absolutely sure of what you are doing.",IDC_STATIC,12,180,264,12 - PUSHBUTTON "&Check for Updates",IDC_BUTTON1,6,204,84,18 - LTEXT "",IDC_LASTUPDATE,6,228,276,48 + CONTROL "Enable online Update &Check",IDC_CHECK_UPDATEENABLED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,6,105,10 + GROUPBOX "Update Channel",IDC_STATIC_UDATECHANNEL,6,18,276,54 + CONTROL "release: official stable released versions only (recommended)",IDC_RADIO1, + "Button",BS_AUTORADIOBUTTON,12,30,211,10 + CONTROL "next: previews of the next official stable release",IDC_RADIO2, + "Button",BS_AUTORADIOBUTTON,12,42,171,10 + CONTROL "development: bleeding-edge development versions",IDC_RADIO3, + "Button",BS_AUTORADIOBUTTON,12,54,179,10 + GROUPBOX "Check for Updates",IDC_STATIC_UPDATECHECK,6,72,276,48 + LTEXT "&Automatically check on program start:",IDC_STATIC_UPDATEFREQUENCY,12,84,126,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_UPDATEFREQUENCY,138,84,42,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Check now",IDC_BUTTON1,222,84,54,12 + LTEXT "",IDC_LASTUPDATE,12,102,264,12 + GROUPBOX "Privacy Settings",IDC_STATIC_UPDATEPRIVACY,6,120,276,156 + CONTROL "&Allow OpenMPT to collect basic statistics about your system configuration",IDC_CHECK1, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,132,264,12 + LTEXT "",IDC_STATIC_UPDATEPRIVACYTEXT,12,144,264,36 + EDITTEXT IDC_EDIT_STATISTICS,12,180,264,90,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_CLOSEDOCUMENTS DIALOGEX 0, 0, 370, 197 @@ -881,7 +884,12 @@ 0 END +IDD_OPTIONS_UPDATE AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // // Dialog Info Index: mptrack/resource.h =================================================================== --- mptrack/resource.h (revision 10676) +++ mptrack/resource.h (working copy) @@ -973,6 +973,13 @@ #define IDC_BUTTON_TUNING_REMOVE 2501 #define IDC_STATIC_WINE_RTAUDIO 2502 #define IDC_COMBO_WINE_RTAUDIO 2503 +#define IDC_STATIC_UPDATECHECK 2504 +#define IDC_STATIC_UPDATEPRIVACY 2505 +#define IDC_STATIC_UDATECHANNEL 2506 +#define IDC_COMBO_UPDATEFREQUENCY 2507 +#define IDC_STATIC_UPDATEFREQUENCY 2508 +#define IDC_CHECK_UPDATEENABLED 2509 +#define IDC_STATIC_UPDATEPRIVACYTEXT 2510 #define ID_FILE_NEWMOD 32771 #define ID_FILE_NEWXM 32772 #define ID_FILE_NEWS3M 32773 @@ -1267,9 +1274,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 542 +#define _APS_NEXT_RESOURCE_VALUE 543 #define _APS_NEXT_COMMAND_VALUE 44646 -#define _APS_NEXT_CONTROL_VALUE 2504 +#define _APS_NEXT_CONTROL_VALUE 2511 #define _APS_NEXT_SYMED_VALUE 901 #endif #endif Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 10676) +++ mptrack/TrackerSettings.cpp (working copy) @@ -331,9 +331,16 @@ , vstHostVendorString(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorString"), "OpenMPT project") , vstHostVendorVersion(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorVersion"), Version::Current().GetRawVersion()) // Update + , UpdateEnabled(conf, MPT_USTRING("Update"), MPT_USTRING("Enabled"), true) , UpdateLastUpdateCheck(conf, MPT_USTRING("Update"), MPT_USTRING("LastUpdateCheck"), mpt::Date::Unix(time_t())) - , UpdateUpdateCheckPeriod(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) - , UpdateUpdateURL(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultUpdateURL()) + , UpdateUpdateCheckPeriod_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) + , UpdateIntervalDays(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriodDays"), 7) + , UpdateChannel(conf, MPT_USTRING("Update"), MPT_USTRING("Channel"), UpdateChannelRelease) + , UpdateUpdateURL_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelReleaseURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelNextURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) + , UpdateChannelDevelopmentURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) + , UpdateAPIURL(conf, MPT_USTRING("Update"), MPT_USTRING("APIURL"), CUpdateCheck::GetDefaultAPIURL()) , UpdateSendGUID(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), true) , UpdateShowUpdateHint(conf, MPT_USTRING("Update"), MPT_USTRING("ShowUpdateHint"), true) , UpdateSuggestDifferentBuildVariant(conf, MPT_USTRING("Update"), MPT_USTRING("SuggestDifferentBuildVariant"), true) @@ -644,6 +651,45 @@ m_dwPatternSetup &= ~0x200; } + // Update + if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,29)) + { + if(UpdateUpdateCheckPeriod_DEPRECATED <= 0) + { + UpdateEnabled = true; + UpdateIntervalDays = -1; + } else + { + UpdateEnabled = true; + UpdateIntervalDays = UpdateUpdateCheckPeriod_DEPRECATED.Get(); + } + if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://www.soal.org/openmpt/OpenMPTversionCheck.php5")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else + { + UpdateChannel = UpdateChannelDevelopment; + UpdateChannelDevelopmentURL = UpdateUpdateURL_DEPRECATED.Get(); + } + conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); + conf.Forget(UpdateUpdateURL_DEPRECATED.GetPath()); + } + // Effects #ifndef NO_EQ FixupEQ(m_EqSettings); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 10676) +++ mptrack/TrackerSettings.h (working copy) @@ -817,9 +817,16 @@ // Update + Setting<bool> UpdateEnabled; Setting<mpt::Date::Unix> UpdateLastUpdateCheck; - Setting<int32> UpdateUpdateCheckPeriod; - Setting<mpt::ustring> UpdateUpdateURL; + Setting<int32> UpdateUpdateCheckPeriod_DEPRECATED; + Setting<int32> UpdateIntervalDays; + Setting<uint32> UpdateChannel; + Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; + Setting<mpt::ustring> UpdateChannelReleaseURL; + Setting<mpt::ustring> UpdateChannelNextURL; + Setting<mpt::ustring> UpdateChannelDevelopmentURL; + Setting<mpt::ustring> UpdateAPIURL; Setting<bool> UpdateSendGUID; Setting<bool> UpdateShowUpdateHint; Setting<bool> UpdateSuggestDifferentBuildVariant; Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 10676) +++ mptrack/UpdateCheck.cpp (working copy) @@ -13,6 +13,7 @@ #include "BuildVariants.h" #include "../common/version.h" #include "../common/misc_util.h" +#include "../common/mptStringBuffer.h" #include "Mptrack.h" #include "TrackerSettings.h" // Setup dialog stuff @@ -19,6 +20,7 @@ #include "Mainfrm.h" #include "../common/mptThread.h" #include "HTTP.h" +#include "../misc/JSON.h" OPENMPT_NAMESPACE_BEGIN @@ -84,12 +86,28 @@ -mpt::ustring CUpdateCheck::GetDefaultUpdateURL() +mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() { return MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID"); } +mpt::ustring CUpdateCheck::GetDefaultChannelNextURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/next/$VERSION/$GUID"); +} +mpt::ustring CUpdateCheck::GetDefaultChannelDevelopmentURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID"); +} + + +mpt::ustring CUpdateCheck::GetDefaultAPIURL() +{ + return MPT_USTRING("https://update.openmpt.org/api/v3/"); +} + + std::atomic<int32> CUpdateCheck::s_InstanceCount(0); @@ -104,11 +122,15 @@ { if(isAutoUpdate) { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(updateCheckPeriod == 0) + if(!TrackerSettings::Instance().UpdateEnabled) { return; } + int updateCheckPeriod = TrackerSettings::Instance().UpdateIntervalDays; + if(updateCheckPeriod < 0) + { + updateCheckPeriod = 0; + } // Do we actually need to run the update check right now? const time_t now = time(nullptr); if(difftime(now, TrackerSettings::Instance().UpdateLastUpdateCheck.Get()) < (double)(updateCheckPeriod * 86400)) @@ -121,7 +143,7 @@ { TrackerSettings::Instance().UpdateShowUpdateHint = false; CString msg; - msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateUpdateCheckPeriod.Get()); + msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateIntervalDays.Get()); if(Reporting::Confirm(msg, _T("OpenMPT Internet Update")) == cnfNo) { TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(now); @@ -128,6 +150,15 @@ return; } } + } else + { + if(!TrackerSettings::Instance().UpdateEnabled) + { + if(Reporting::Confirm(_T("Update Check is disabled. Do you want to check anyway?"), _T("OpenMPT Internet Update")) != cnfYes) + { + return; + } + } } TrackerSettings::Instance().UpdateShowUpdateHint = false; @@ -137,22 +168,33 @@ return; } - CUpdateCheck::Settings settings; - settings.window = CMainFrame::GetMainFrame(); - settings.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; - settings.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; - settings.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; - settings.autoUpdate = isAutoUpdate; - settings.updateBaseURL = TrackerSettings::Instance().UpdateUpdateURL; - settings.sendStatistics = TrackerSettings::Instance().UpdateSendGUID; - settings.statisticsUUID = TrackerSettings::Instance().VersionInstallGUID; - settings.suggestDifferentBuilds = TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant; - std::thread(CUpdateCheck::ThreadFunc(settings)).detach(); + CUpdateCheck::Context context; + context.window = CMainFrame::GetMainFrame(); + context.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; + context.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; + context.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; + context.autoUpdate = isAutoUpdate; + std::thread(CUpdateCheck::ThreadFunc(CUpdateCheck::Settings(), context)).detach(); } -CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings) +CUpdateCheck::Settings::Settings() + : periodDays(TrackerSettings::Instance().UpdateIntervalDays) + , channel(TrackerSettings::Instance().UpdateChannel) + , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) + , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) + , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) + , apiURL(TrackerSettings::Instance().UpdateAPIURL) + , sendStatistics(TrackerSettings::Instance().UpdateSendGUID) + , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) + , suggestDifferentBuilds(TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant) +{ +} + + +CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) : settings(settings) + , context(context) { return; } @@ -160,27 +202,104 @@ void CUpdateCheck::ThreadFunc::operator () () { - mpt::SetCurrentThreadPriority(settings.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); - CUpdateCheck::CheckForUpdate(settings); + mpt::SetCurrentThreadPriority(context.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); + CUpdateCheck::CheckForUpdate(settings, context); } -// Run update check (independent thread) -CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +std::string CUpdateCheck::GetStatisticsDataV3(const Settings &settings) { - - HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + JSON::value j; + j["OpenMPT"]["Version"] = mpt::ufmt::val(Version::Current()); + j["OpenMPT"]["BuildVariant"] = BuildVariants().GuessCurrentBuildName(); + j["OpenMPT"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetProcessArchitecture()); + j["Update"]["PeriodDays"] = settings.periodDays; + j["System"]["Windows"]["Version"]["Name"] = mpt::Windows::Version::Current().GetName(); + j["System"]["Windows"]["Version"]["Major"] = mpt::Windows::Version::Current().GetSystem().Major; + j["System"]["Windows"]["Version"]["Minor"] = mpt::Windows::Version::Current().GetSystem().Minor; + j["System"]["Windows"]["ServicePack"]["Major"] = mpt::Windows::Version::Current().GetServicePack().Major; + j["System"]["Windows"]["ServicePack"]["Minor"] = mpt::Windows::Version::Current().GetServicePack().Minor; + j["System"]["Windows"]["Build"] = mpt::Windows::Version::Current().GetBuild(); + j["System"]["Windows"]["IsWine"] = mpt::Windows::IsWine(); + if(mpt::Windows::IsWine()) + { + mpt::Wine::VersionContext v; + j["System"]["Windows"]["Wine"]["Version"]["Raw"] = v.RawVersion(); + if(v.Version().IsValid()) + { + j["System"]["Windows"]["Wine"]["Version"]["Major"] = v.Version().GetMajor(); + j["System"]["Windows"]["Wine"]["Version"]["Minor"] = v.Version().GetMinor(); + j["System"]["Windows"]["Wine"]["Version"]["Update"] = v.Version().GetUpdate(); + } + j["System"]["Windows"]["Wine"]["HostSysName"] = v.RawHostSysName(); + } + j["System"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetHostArchitecture()); + MEMORYSTATUSEX memoryStatus; + MemsetZero(memoryStatus); + memoryStatus.dwLength = sizeof(MEMORYSTATUSEX); + if(GlobalMemoryStatusEx(&memoryStatus) != 0) + { + j["System"]["Memory"] = memoryStatus.ullTotalPhys / 1024 / 1024; + } + #ifdef ENABLE_ASM + j["System"]["Processor"]["Vendor"] = std::string(mpt::String::ReadAutoBuf(ProcVendorID)); + j["System"]["Processor"]["Brand"] = std::string(mpt::String::ReadAutoBuf(ProcBrandID)); + j["System"]["Processor"]["Family"] = ProcFamily; + j["System"]["Processor"]["Model"] = ProcModel; + j["System"]["Processor"]["Stepping"] = ProcStepping; + j["System"]["Processor"]["Features"]["tsc"] = ((GetRealProcSupport() & PROCSUPPORT_TSC) ? true : false); + j["System"]["Processor"]["Features"]["cmov"] = ((GetRealProcSupport() & PROCSUPPORT_CMOV) ? true : false); + j["System"]["Processor"]["Features"]["mmx"] = ((GetRealProcSupport() & PROCSUPPORT_MMX) ? true : false); + j["System"]["Processor"]["Features"]["mmxext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_MMXEXT) ? true : false); + j["System"]["Processor"]["Features"]["3dnow"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOW) ? true : false); + j["System"]["Processor"]["Features"]["3dnowext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOWEXT) ? true : false); + j["System"]["Processor"]["Features"]["sse"] = ((GetRealProcSupport() & PROCSUPPORT_SSE) ? true : false); + j["System"]["Processor"]["Features"]["sse2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE2) ? true : false); + j["System"]["Processor"]["Features"]["sse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSE3) ? true : false); + j["System"]["Processor"]["Features"]["ssse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSSE3) ? true : false); + j["System"]["Processor"]["Features"]["sse4_1"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_1) ? true : false); + j["System"]["Processor"]["Features"]["sse4_2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_2) ? true : false); + #endif + return j.dump(1, '\t'); +} - mpt::ustring updateURL = settings.updateBaseURL; - if(updateURL.empty()) + +mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) +{ + mpt::ustring updateURL; + if(settings.channel == UpdateChannelRelease) { - updateURL = GetDefaultUpdateURL(); + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } + } else if(settings.channel == UpdateChannelNext) + { + updateURL = settings.channelNextURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelNextURL(); + } + } else if(settings.channel == UpdateChannelDevelopment) + { + updateURL = settings.channelDevelopmentURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelDevelopmentURL(); + } + } else + { + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } } if(updateURL.find(MPT_USTRING("://")) == mpt::ustring::npos) { updateURL = MPT_USTRING("https://") + updateURL; } - // Build update URL updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$VERSION"), mpt::uformat(MPT_USTRING("%1-%2-%3")) ( Version::Current() @@ -188,15 +307,44 @@ , settings.sendStatistics ? mpt::Windows::Version::Current().GetNameShort() : MPT_USTRING("unknown") )); updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : MPT_USTRING("anonymous")); + return updateURL; +} + +// Run update check (independent thread) +CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +{ + + HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + // Establish a connection. HTTP::Request request; - request.SetURI(ParseURI(updateURL)); + request.SetURI(ParseURI(GetUpdateURLV2(settings))); request.method = HTTP::Method::Get; request.flags = HTTP::NoCache; HTTP::Result resultHTTP = internet(request.InsecureTLSDowngradeWindowsXP()); + if(settings.sendStatistics) + { + HTTP::Request requestStatistics; + if(settings.statisticsUUID.IsValid()) + { + requestStatistics.SetURI(ParseURI(settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID))); + requestStatistics.method = HTTP::Method::Put; + } else + { + requestStatistics.SetURI(ParseURI(settings.apiURL + MPT_USTRING("statistics/"))); + requestStatistics.method = HTTP::Method::Post; + } + requestStatistics.dataMimeType = HTTP::MimeType::JSON(); + requestStatistics.acceptMimeTypes = HTTP::MimeTypes::JSON(); + std::string jsondata = GetStatisticsDataV3(settings); + MPT_LOG(LogInformation, "Update", mpt::ToUnicode(mpt::CharsetUTF8, jsondata)); + requestStatistics.data = mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(jsondata)); + internet(requestStatistics.InsecureTLSDowngradeWindowsXP()); + } + // Retrieve HTTP status code. if(resultHTTP.Status >= 400) { @@ -244,12 +392,12 @@ } -void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings) +void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) { // �ncremented before starting the thread MPT_ASSERT(s_InstanceCount.load() >= 1); CUpdateCheck::Result result; - settings.window->SendMessage(settings.msgProgress, settings.autoUpdate ? 1 : 0, s_InstanceCount.load()); + context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, s_InstanceCount.load()); try { try @@ -264,12 +412,12 @@ } } catch(const CUpdateCheck::Error &e) { - settings.window->SendMessage(settings.msgFailure, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); + context.window->SendMessage(context.msgFailure, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); return; } - settings.window->SendMessage(settings.msgSuccess, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); + context.window->SendMessage(context.msgSuccess, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); } @@ -347,14 +495,13 @@ // CUpdateSetupDlg BEGIN_MESSAGE_MAP(CUpdateSetupDlg, CPropertyPage) - ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) - ON_COMMAND(IDC_BUTTON2, &CUpdateSetupDlg::OnResetURL) - ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO4, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) - ON_EN_CHANGE(IDC_EDIT1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK_UPDATEENABLED, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) + ON_CBN_SELCHANGE(IDC_COMBO_UPDATEFREQUENCY, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) END_MESSAGE_MAP() @@ -366,29 +513,82 @@ } +void CUpdateSetupDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO_UPDATEFREQUENCY, m_CbnUpdateFrequency); +} + + BOOL CUpdateSetupDlg::OnInitDialog() { CPropertyPage::OnInitDialog(); + CheckDlgButton(IDC_CHECK_UPDATEENABLED, TrackerSettings::Instance().UpdateEnabled ? BST_CHECKED : BST_UNCHECKED); + int radioID = 0; - int periodDays = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(periodDays >= 30) + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(updateChannel == UpdateChannelRelease) { - radioID = IDC_RADIO4; - } else if(periodDays >= 7) + radioID = IDC_RADIO1; + } else if(updateChannel == UpdateChannelNext) { + radioID = IDC_RADIO2; + } else if(updateChannel == UpdateChannelDevelopment) + { radioID = IDC_RADIO3; - } else if(periodDays >= 1) - { - radioID = IDC_RADIO2; } else { radioID = IDC_RADIO1; } - CheckRadioButton(IDC_RADIO1, IDC_RADIO4, radioID); + CheckRadioButton(IDC_RADIO1, IDC_RADIO3, radioID); + + int32 periodDays = TrackerSettings::Instance().UpdateIntervalDays; + int ndx; + + ndx = m_CbnUpdateFrequency.AddString(_T("always")); + m_CbnUpdateFrequency.SetItemData(ndx, 0); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("daily")); + m_CbnUpdateFrequency.SetItemData(ndx, 1); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("weekly")); + m_CbnUpdateFrequency.SetItemData(ndx, 7); + if(periodDays >= 7) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("monthly")); + m_CbnUpdateFrequency.SetItemData(ndx, 30); + if(periodDays >= 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("never")); + m_CbnUpdateFrequency.SetItemData(ndx, ~(DWORD_PTR)0); + if(periodDays < 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateSendGUID ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(IDC_EDIT1, mpt::ToCString(TrackerSettings::Instance().UpdateUpdateURL.Get())); + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->SetWindowText(_T("A randomized user ID is created and transmitted alongside. This ID can only be linked to you or your computer by this very ID, which is stored solely on your computer. OpenMPT will use this information to gather usage statistics and to plan removal of support for older systems. The following information will be sent:")); + + UpdateStatistics(); + + EnableDisableDialog(); + m_SettingChangedNotifyGuard.Register(this); SettingChanged(TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()); @@ -396,6 +596,43 @@ } +void CUpdateSetupDlg::UpdateStatistics() +{ + CUpdateCheck::Settings settings; + + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + + CString updateURL; + GetDlgItemText(IDC_EDIT1, updateURL); + + settings.periodDays = updateCheckPeriod; + settings.channel = updateChannel; + settings.sendStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); + + mpt::ustring statistics; + statistics += MPT_USTRING("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + MPT_ULITERAL("\n"); + statistics += MPT_ULITERAL("\n"); + if(settings.sendStatistics) + { + if(settings.statisticsUUID.IsValid()) + { + statistics += MPT_USTRING("PUT ") + settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID) + MPT_ULITERAL("\n"); + } else + { + statistics += MPT_USTRING("POST ") + settings.apiURL + MPT_USTRING("statistics/") + MPT_ULITERAL("\n"); + } + statistics += mpt::String::Replace(mpt::ToUnicode(mpt::CharsetUTF8, CUpdateCheck::GetStatisticsDataV3(settings)), MPT_USTRING("\t"), MPT_USTRING(" ")); + statistics += MPT_ULITERAL("\n"); + } + SetDlgItemText(IDC_EDIT_STATISTICS, mpt::ToCString(mpt::String::Replace(statistics, MPT_USTRING("\n"), MPT_USTRING("\r\n")))); +} + + void CUpdateSetupDlg::SettingChanged(const SettingPath &changedPath) { if(changedPath == TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()) @@ -420,19 +657,42 @@ } +void CUpdateSetupDlg::EnableDisableDialog() +{ + + /* + BOOL status = ((IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED) ? TRUE : FALSE); + */ + + GetDlgItem(IDC_CHECK_UPDATEENABLED)->EnableWindow(FALSE); + GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); + +} + + +void CUpdateSetupDlg::OnSettingsChanged() +{ + EnableDisableDialog(); + UpdateStatistics(); + SetModified(TRUE); +} + + void CUpdateSetupDlg::OnOK() { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(IsDlgButtonChecked(IDC_RADIO1)) updateCheckPeriod = 0; - if(IsDlgButtonChecked(IDC_RADIO2)) updateCheckPeriod = 1; - if(IsDlgButtonChecked(IDC_RADIO3)) updateCheckPeriod = 7; - if(IsDlgButtonChecked(IDC_RADIO4)) updateCheckPeriod = 31; + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())) : -1; + CString updateURL; GetDlgItemText(IDC_EDIT1, updateURL); - TrackerSettings::Instance().UpdateUpdateCheckPeriod = updateCheckPeriod; - TrackerSettings::Instance().UpdateUpdateURL = mpt::ToUnicode(updateURL); + TrackerSettings::Instance().UpdateEnabled = (IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED); + TrackerSettings::Instance().UpdateIntervalDays = updateCheckPeriod; + TrackerSettings::Instance().UpdateChannel = updateChannel; TrackerSettings::Instance().UpdateSendGUID = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); CPropertyPage::OnOK(); @@ -452,10 +712,4 @@ } -void CUpdateSetupDlg::OnResetURL() -{ - SetDlgItemText(IDC_EDIT1, mpt::ToCString(CUpdateCheck::GetDefaultUpdateURL())); -} - - OPENMPT_NAMESPACE_END Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 10676) +++ mptrack/UpdateCheck.h (working copy) @@ -24,6 +24,13 @@ OPENMPT_NAMESPACE_BEGIN +enum UpdateChannel +{ + UpdateChannelRelease = 1, + UpdateChannelNext = 2, + UpdateChannelDevelopment = 3, +}; + class CUpdateCheck { @@ -33,7 +40,11 @@ public: - static mpt::ustring GetDefaultUpdateURL(); + static mpt::ustring GetDefaultChannelReleaseURL(); + static mpt::ustring GetDefaultChannelNextURL(); + static mpt::ustring GetDefaultChannelDevelopmentURL(); + + static mpt::ustring GetDefaultAPIURL(); int32 GetNumCurrentRunningInstances(); @@ -42,7 +53,7 @@ public: - struct Settings + struct Context { CWnd *window; UINT msgProgress; @@ -49,10 +60,20 @@ UINT msgSuccess; UINT msgFailure; bool autoUpdate; - mpt::ustring updateBaseURL; // URL where the version check should be made. + }; + + struct Settings + { + int32 periodDays; + uint32 channel; + mpt::ustring channelReleaseURL; + mpt::ustring channelNextURL; + mpt::ustring channelDevelopmentURL; + mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; bool suggestDifferentBuilds; + Settings(); }; class Error @@ -86,6 +107,14 @@ static void ShowSuccessGUI(WPARAM wparam, LPARAM lparam); static void ShowFailureGUI(WPARAM wparam, LPARAM lparam); +public: + + // v2 + static mpt::ustring GetUpdateURLV2(const Settings &settings); + + // v3 + static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 + protected: static void StartUpdateCheckAsync(bool autoUpdate); @@ -93,11 +122,12 @@ struct ThreadFunc { CUpdateCheck::Settings settings; - ThreadFunc(const CUpdateCheck::Settings &settings); + CUpdateCheck::Context context; + ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); void operator () (); }; - static void CheckForUpdate(const CUpdateCheck::Settings &settings); + static void CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); static CUpdateCheck::Result SearchUpdate(const CUpdateCheck::Settings &settings); // may throw @@ -111,17 +141,20 @@ CUpdateSetupDlg(); protected: + virtual void DoDataExchange(CDataExchange *pDX); virtual BOOL OnInitDialog(); virtual void OnOK(); virtual BOOL OnSetActive(); - afx_msg void OnSettingsChanged() { SetModified(TRUE); } + afx_msg void OnSettingsChanged(); afx_msg void OnCheckNow(); - afx_msg void OnResetURL(); virtual void SettingChanged(const SettingPath &changedPath); + void EnableDisableDialog(); + void UpdateStatistics(); DECLARE_MESSAGE_MAP() private: SettingChangedNotifyGuard m_SettingChangedNotifyGuard; + CComboBox m_CbnUpdateFrequency; }; Index: mptrack/WelcomeDialog.cpp =================================================================== --- mptrack/WelcomeDialog.cpp (revision 10676) +++ mptrack/WelcomeDialog.cpp (working copy) @@ -147,7 +147,7 @@ CDialog::OnOK(); bool runUpdates = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED; - TrackerSettings::Instance().UpdateUpdateCheckPeriod = (runUpdates ? 7 : 0); + TrackerSettings::Instance().UpdateIntervalDays = (runUpdates ? 7 : 0); if(IsDlgButtonChecked(IDC_CHECK2) != BST_UNCHECKED) { FontSetting font = TrackerSettings::Instance().patternFont; update-statistics-v3.patch (35,294 bytes)
Index: common/versionNumber.h =================================================================== --- common/versionNumber.h (revision 10769) +++ common/versionNumber.h (working copy) @@ -21,7 +21,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 28 #define VER_MINOR 00 -#define VER_MINORMINOR 31 +#define VER_MINORMINOR 32 //Numerical value of the version. #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR) Index: mptrack/mptrack.rc =================================================================== --- mptrack/mptrack.rc (revision 10769) +++ mptrack/mptrack.rc (working copy) @@ -244,22 +244,25 @@ CAPTION "Update" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Check for Updates",IDC_STATIC,6,6,276,66 - CONTROL "&Never",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,12,18,240,8 - CONTROL "&Daily",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,12,30,240,8 - CONTROL "&Weekly (recommended)",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,12,42,240,8 - CONTROL "&Monthly",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,12,54,240,8 - GROUPBOX "Privacy Settings",IDC_STATIC,6,78,276,54 - CONTROL "&Allow us to collect basic update statistics",IDC_CHECK1, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,90,246,12 - LTEXT "If enabled, a randomized user ID is created and transmitted with every update check. This ID can not be linked to you or your computer in any way.",IDC_STATIC,12,102,264,24 - GROUPBOX "Advanced Settings",IDC_STATIC,6,138,276,60 - LTEXT "&Update server URL:",IDC_STATIC,12,150,186,8 - EDITTEXT IDC_EDIT1,12,162,264,12,ES_AUTOHSCROLL - PUSHBUTTON "&Reset",IDC_BUTTON2,222,146,54,12 - LTEXT "Do not change this unless you are absolutely sure of what you are doing.",IDC_STATIC,12,180,264,12 - PUSHBUTTON "&Check for Updates",IDC_BUTTON1,6,204,84,18 - LTEXT "",IDC_LASTUPDATE,6,228,276,48 + CONTROL "Enable online Update &Check",IDC_CHECK_UPDATEENABLED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,6,105,10 + GROUPBOX "Update Channel",IDC_STATIC_UDATECHANNEL,6,18,276,54 + CONTROL "release: official stable released versions only (recommended)",IDC_RADIO1, + "Button",BS_AUTORADIOBUTTON,12,30,211,10 + CONTROL "next: previews of the next official stable release",IDC_RADIO2, + "Button",BS_AUTORADIOBUTTON,12,42,171,10 + CONTROL "development: bleeding-edge development versions",IDC_RADIO3, + "Button",BS_AUTORADIOBUTTON,12,54,179,10 + GROUPBOX "Check for Updates",IDC_STATIC_UPDATECHECK,6,72,276,48 + LTEXT "&Automatically check on program start:",IDC_STATIC_UPDATEFREQUENCY,12,84,126,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_UPDATEFREQUENCY,138,84,42,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Check now...",IDC_BUTTON1,216,84,60,12 + LTEXT "",IDC_LASTUPDATE,12,102,264,12 + GROUPBOX "Privacy Settings",IDC_STATIC_UPDATEPRIVACY,6,120,276,156 + CONTROL "&Allow OpenMPT to collect basic statistics about your system configuration",IDC_CHECK1, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,132,264,12 + LTEXT "",IDC_STATIC_UPDATEPRIVACYTEXT,12,144,264,36 + EDITTEXT IDC_EDIT_STATISTICS,12,180,264,90,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_CLOSEDOCUMENTS DIALOGEX 0, 0, 370, 197 @@ -881,7 +884,12 @@ 0 END +IDD_OPTIONS_UPDATE AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // // Dialog Info Index: mptrack/resource.h =================================================================== --- mptrack/resource.h (revision 10769) +++ mptrack/resource.h (working copy) @@ -974,6 +974,13 @@ #define IDC_BUTTON_TUNING_REMOVE 2501 #define IDC_STATIC_WINE_RTAUDIO 2502 #define IDC_COMBO_WINE_RTAUDIO 2503 +#define IDC_STATIC_UPDATECHECK 2504 +#define IDC_STATIC_UPDATEPRIVACY 2505 +#define IDC_STATIC_UDATECHANNEL 2506 +#define IDC_COMBO_UPDATEFREQUENCY 2507 +#define IDC_STATIC_UPDATEFREQUENCY 2508 +#define IDC_CHECK_UPDATEENABLED 2509 +#define IDC_STATIC_UPDATEPRIVACYTEXT 2510 #define ID_FILE_NEWMOD 32771 #define ID_FILE_NEWXM 32772 #define ID_FILE_NEWS3M 32773 @@ -1268,9 +1275,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 542 +#define _APS_NEXT_RESOURCE_VALUE 543 #define _APS_NEXT_COMMAND_VALUE 44646 -#define _APS_NEXT_CONTROL_VALUE 2504 +#define _APS_NEXT_CONTROL_VALUE 2511 #define _APS_NEXT_SYMED_VALUE 901 #endif #endif Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 10769) +++ mptrack/TrackerSettings.cpp (working copy) @@ -331,10 +331,17 @@ , vstHostVendorString(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorString"), "OpenMPT project") , vstHostVendorVersion(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorVersion"), Version::Current().GetRawVersion()) // Update + , UpdateEnabled(conf, MPT_USTRING("Update"), MPT_USTRING("Enabled"), true) , UpdateLastUpdateCheck(conf, MPT_USTRING("Update"), MPT_USTRING("LastUpdateCheck"), mpt::Date::Unix(time_t())) - , UpdateUpdateCheckPeriod(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) - , UpdateUpdateURL(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultUpdateURL()) - , UpdateSendGUID(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), true) + , UpdateUpdateCheckPeriod_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) + , UpdateIntervalDays(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriodDays"), 7) + , UpdateChannel(conf, MPT_USTRING("Update"), MPT_USTRING("Channel"), UpdateChannelRelease) + , UpdateUpdateURL_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelReleaseURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelNextURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) + , UpdateChannelDevelopmentURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) + , UpdateAPIURL(conf, MPT_USTRING("Update"), MPT_USTRING("APIURL"), CUpdateCheck::GetDefaultAPIURL()) + , UpdateSendGUID(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), false) , UpdateShowUpdateHint(conf, MPT_USTRING("Update"), MPT_USTRING("ShowUpdateHint"), true) , UpdateSuggestDifferentBuildVariant(conf, MPT_USTRING("Update"), MPT_USTRING("SuggestDifferentBuildVariant"), true) , UpdateIgnoreVersion(conf, MPT_USTRING("Update"), MPT_USTRING("IgnoreVersion"), _T("")) @@ -644,6 +651,45 @@ m_dwPatternSetup &= ~0x200; } + // Update + if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,32)) + { + if(UpdateUpdateCheckPeriod_DEPRECATED <= 0) + { + UpdateEnabled = true; + UpdateIntervalDays = -1; + } else + { + UpdateEnabled = true; + UpdateIntervalDays = UpdateUpdateCheckPeriod_DEPRECATED.Get(); + } + if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://www.soal.org/openmpt/OpenMPTversionCheck.php5")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else + { + UpdateChannel = UpdateChannelDevelopment; + UpdateChannelDevelopmentURL = UpdateUpdateURL_DEPRECATED.Get(); + } + conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); + conf.Forget(UpdateUpdateURL_DEPRECATED.GetPath()); + } + // Effects #ifndef NO_EQ FixupEQ(m_EqSettings); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 10769) +++ mptrack/TrackerSettings.h (working copy) @@ -817,9 +817,16 @@ // Update + Setting<bool> UpdateEnabled; Setting<mpt::Date::Unix> UpdateLastUpdateCheck; - Setting<int32> UpdateUpdateCheckPeriod; - Setting<mpt::ustring> UpdateUpdateURL; + Setting<int32> UpdateUpdateCheckPeriod_DEPRECATED; + Setting<int32> UpdateIntervalDays; + Setting<uint32> UpdateChannel; + Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; + Setting<mpt::ustring> UpdateChannelReleaseURL; + Setting<mpt::ustring> UpdateChannelNextURL; + Setting<mpt::ustring> UpdateChannelDevelopmentURL; + Setting<mpt::ustring> UpdateAPIURL; Setting<bool> UpdateSendGUID; Setting<bool> UpdateShowUpdateHint; Setting<bool> UpdateSuggestDifferentBuildVariant; Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 10769) +++ mptrack/UpdateCheck.cpp (working copy) @@ -13,6 +13,7 @@ #include "BuildVariants.h" #include "../common/version.h" #include "../common/misc_util.h" +#include "../common/mptStringBuffer.h" #include "Mptrack.h" #include "TrackerSettings.h" // Setup dialog stuff @@ -19,6 +20,7 @@ #include "Mainfrm.h" #include "../common/mptThread.h" #include "HTTP.h" +#include "../misc/JSON.h" OPENMPT_NAMESPACE_BEGIN @@ -84,12 +86,28 @@ -mpt::ustring CUpdateCheck::GetDefaultUpdateURL() +mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() { return MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID"); } +mpt::ustring CUpdateCheck::GetDefaultChannelNextURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/next/$VERSION/$GUID"); +} +mpt::ustring CUpdateCheck::GetDefaultChannelDevelopmentURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID"); +} + + +mpt::ustring CUpdateCheck::GetDefaultAPIURL() +{ + return MPT_USTRING("https://update.openmpt.org/api/v3/"); +} + + std::atomic<int32> CUpdateCheck::s_InstanceCount(0); @@ -104,11 +122,15 @@ { if(isAutoUpdate) { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(updateCheckPeriod == 0) + if(!TrackerSettings::Instance().UpdateEnabled) { return; } + int updateCheckPeriod = TrackerSettings::Instance().UpdateIntervalDays; + if(updateCheckPeriod < 0) + { + return; + } // Do we actually need to run the update check right now? const time_t now = time(nullptr); if(difftime(now, TrackerSettings::Instance().UpdateLastUpdateCheck.Get()) < (double)(updateCheckPeriod * 86400)) @@ -121,7 +143,7 @@ { TrackerSettings::Instance().UpdateShowUpdateHint = false; CString msg; - msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateUpdateCheckPeriod.Get()); + msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateIntervalDays.Get()); if(Reporting::Confirm(msg, _T("OpenMPT Internet Update")) == cnfNo) { TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(now); @@ -128,6 +150,15 @@ return; } } + } else + { + if(!TrackerSettings::Instance().UpdateEnabled) + { + if(Reporting::Confirm(_T("Update Check is disabled. Do you want to check anyway?"), _T("OpenMPT Internet Update")) != cnfYes) + { + return; + } + } } TrackerSettings::Instance().UpdateShowUpdateHint = false; @@ -137,22 +168,33 @@ return; } - CUpdateCheck::Settings settings; - settings.window = CMainFrame::GetMainFrame(); - settings.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; - settings.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; - settings.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; - settings.autoUpdate = isAutoUpdate; - settings.updateBaseURL = TrackerSettings::Instance().UpdateUpdateURL; - settings.sendStatistics = TrackerSettings::Instance().UpdateSendGUID; - settings.statisticsUUID = TrackerSettings::Instance().VersionInstallGUID; - settings.suggestDifferentBuilds = TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant; - std::thread(CUpdateCheck::ThreadFunc(settings)).detach(); + CUpdateCheck::Context context; + context.window = CMainFrame::GetMainFrame(); + context.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; + context.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; + context.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; + context.autoUpdate = isAutoUpdate; + std::thread(CUpdateCheck::ThreadFunc(CUpdateCheck::Settings(), context)).detach(); } -CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings) +CUpdateCheck::Settings::Settings() + : periodDays(TrackerSettings::Instance().UpdateIntervalDays) + , channel(TrackerSettings::Instance().UpdateChannel) + , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) + , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) + , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) + , apiURL(TrackerSettings::Instance().UpdateAPIURL) + , sendStatistics(TrackerSettings::Instance().UpdateSendGUID) + , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) + , suggestDifferentBuilds(TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant) +{ +} + + +CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) : settings(settings) + , context(context) { return; } @@ -160,27 +202,103 @@ void CUpdateCheck::ThreadFunc::operator () () { - mpt::SetCurrentThreadPriority(settings.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); - CUpdateCheck::CheckForUpdate(settings); + mpt::SetCurrentThreadPriority(context.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); + CUpdateCheck::CheckForUpdate(settings, context); } -// Run update check (independent thread) -CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +std::string CUpdateCheck::GetStatisticsDataV3(const Settings &settings) { - - HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + JSON::value j; + j["OpenMPT"]["Version"] = mpt::ufmt::val(Version::Current()); + j["OpenMPT"]["BuildVariant"] = BuildVariants().GuessCurrentBuildName(); + j["OpenMPT"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetProcessArchitecture()); + j["Update"]["PeriodDays"] = settings.periodDays; + j["System"]["Windows"]["Version"]["Name"] = mpt::Windows::Version::Current().GetName(); + j["System"]["Windows"]["Version"]["Major"] = mpt::Windows::Version::Current().GetSystem().Major; + j["System"]["Windows"]["Version"]["Minor"] = mpt::Windows::Version::Current().GetSystem().Minor; + j["System"]["Windows"]["ServicePack"]["Major"] = mpt::Windows::Version::Current().GetServicePack().Major; + j["System"]["Windows"]["ServicePack"]["Minor"] = mpt::Windows::Version::Current().GetServicePack().Minor; + j["System"]["Windows"]["Build"] = mpt::Windows::Version::Current().GetBuild(); + j["System"]["Windows"]["IsWine"] = mpt::Windows::IsWine(); + if(mpt::Windows::IsWine()) + { + mpt::Wine::VersionContext v; + j["System"]["Windows"]["Wine"]["Version"]["Raw"] = v.RawVersion(); + if(v.Version().IsValid()) + { + j["System"]["Windows"]["Wine"]["Version"]["Major"] = v.Version().GetMajor(); + j["System"]["Windows"]["Wine"]["Version"]["Minor"] = v.Version().GetMinor(); + j["System"]["Windows"]["Wine"]["Version"]["Update"] = v.Version().GetUpdate(); + } + j["System"]["Windows"]["Wine"]["HostSysName"] = v.RawHostSysName(); + } + j["System"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetHostArchitecture()); + MEMORYSTATUSEX memoryStatus; + MemsetZero(memoryStatus); + memoryStatus.dwLength = sizeof(MEMORYSTATUSEX); + if(GlobalMemoryStatusEx(&memoryStatus) != 0) + { + j["System"]["Memory"] = memoryStatus.ullTotalPhys / 1024 / 1024; + } + #ifdef ENABLE_ASM + j["System"]["Processor"]["Vendor"] = std::string(mpt::String::ReadAutoBuf(ProcVendorID)); + j["System"]["Processor"]["Brand"] = std::string(mpt::String::ReadAutoBuf(ProcBrandID)); + j["System"]["Processor"]["Id"]["Family"] = ProcFamily; + j["System"]["Processor"]["Id"]["Model"] = ProcModel; + j["System"]["Processor"]["Id"]["Stepping"] = ProcStepping; + j["System"]["Processor"]["Features"]["cmov"] = ((GetRealProcSupport() & PROCSUPPORT_CMOV) ? true : false); + j["System"]["Processor"]["Features"]["mmx"] = ((GetRealProcSupport() & PROCSUPPORT_MMX) ? true : false); + j["System"]["Processor"]["Features"]["mmxext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_MMXEXT) ? true : false); + j["System"]["Processor"]["Features"]["3dnow"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOW) ? true : false); + j["System"]["Processor"]["Features"]["3dnowext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOWEXT) ? true : false); + j["System"]["Processor"]["Features"]["sse"] = ((GetRealProcSupport() & PROCSUPPORT_SSE) ? true : false); + j["System"]["Processor"]["Features"]["sse2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE2) ? true : false); + j["System"]["Processor"]["Features"]["sse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSE3) ? true : false); + j["System"]["Processor"]["Features"]["ssse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSSE3) ? true : false); + j["System"]["Processor"]["Features"]["sse4_1"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_1) ? true : false); + j["System"]["Processor"]["Features"]["sse4_2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_2) ? true : false); + #endif + return j.dump(1, '\t'); +} - mpt::ustring updateURL = settings.updateBaseURL; - if(updateURL.empty()) + +mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) +{ + mpt::ustring updateURL; + if(settings.channel == UpdateChannelRelease) { - updateURL = GetDefaultUpdateURL(); + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } + } else if(settings.channel == UpdateChannelNext) + { + updateURL = settings.channelNextURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelNextURL(); + } + } else if(settings.channel == UpdateChannelDevelopment) + { + updateURL = settings.channelDevelopmentURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelDevelopmentURL(); + } + } else + { + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } } if(updateURL.find(MPT_USTRING("://")) == mpt::ustring::npos) { updateURL = MPT_USTRING("https://") + updateURL; } - // Build update URL updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$VERSION"), mpt::uformat(MPT_USTRING("%1-%2-%3")) ( Version::Current() @@ -188,15 +306,44 @@ , settings.sendStatistics ? mpt::Windows::Version::Current().GetNameShort() : MPT_USTRING("unknown") )); updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : MPT_USTRING("anonymous")); + return updateURL; +} + +// Run update check (independent thread) +CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +{ + + HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + // Establish a connection. HTTP::Request request; - request.SetURI(ParseURI(updateURL)); + request.SetURI(ParseURI(GetUpdateURLV2(settings))); request.method = HTTP::Method::Get; request.flags = HTTP::NoCache; HTTP::Result resultHTTP = internet(request.InsecureTLSDowngradeWindowsXP()); + if(settings.sendStatistics) + { + HTTP::Request requestStatistics; + if(settings.statisticsUUID.IsValid()) + { + requestStatistics.SetURI(ParseURI(settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID))); + requestStatistics.method = HTTP::Method::Put; + } else + { + requestStatistics.SetURI(ParseURI(settings.apiURL + MPT_USTRING("statistics/"))); + requestStatistics.method = HTTP::Method::Post; + } + requestStatistics.dataMimeType = HTTP::MimeType::JSON(); + requestStatistics.acceptMimeTypes = HTTP::MimeTypes::JSON(); + std::string jsondata = GetStatisticsDataV3(settings); + MPT_LOG(LogInformation, "Update", mpt::ToUnicode(mpt::CharsetUTF8, jsondata)); + requestStatistics.data = mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(jsondata)); + internet(requestStatistics.InsecureTLSDowngradeWindowsXP()); + } + // Retrieve HTTP status code. if(resultHTTP.Status >= 400) { @@ -244,12 +391,12 @@ } -void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings) +void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) { // �ncremented before starting the thread MPT_ASSERT(s_InstanceCount.load() >= 1); CUpdateCheck::Result result; - settings.window->SendMessage(settings.msgProgress, settings.autoUpdate ? 1 : 0, s_InstanceCount.load()); + context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, s_InstanceCount.load()); try { try @@ -264,12 +411,12 @@ } } catch(const CUpdateCheck::Error &e) { - settings.window->SendMessage(settings.msgFailure, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); + context.window->SendMessage(context.msgFailure, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); return; } - settings.window->SendMessage(settings.msgSuccess, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); + context.window->SendMessage(context.msgSuccess, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); } @@ -347,14 +494,13 @@ // CUpdateSetupDlg BEGIN_MESSAGE_MAP(CUpdateSetupDlg, CPropertyPage) - ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) - ON_COMMAND(IDC_BUTTON2, &CUpdateSetupDlg::OnResetURL) - ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO4, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) - ON_EN_CHANGE(IDC_EDIT1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK_UPDATEENABLED, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) + ON_CBN_SELCHANGE(IDC_COMBO_UPDATEFREQUENCY, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) END_MESSAGE_MAP() @@ -366,29 +512,82 @@ } +void CUpdateSetupDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO_UPDATEFREQUENCY, m_CbnUpdateFrequency); +} + + BOOL CUpdateSetupDlg::OnInitDialog() { CPropertyPage::OnInitDialog(); + CheckDlgButton(IDC_CHECK_UPDATEENABLED, TrackerSettings::Instance().UpdateEnabled ? BST_CHECKED : BST_UNCHECKED); + int radioID = 0; - int periodDays = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(periodDays >= 30) + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(updateChannel == UpdateChannelRelease) { - radioID = IDC_RADIO4; - } else if(periodDays >= 7) + radioID = IDC_RADIO1; + } else if(updateChannel == UpdateChannelNext) { + radioID = IDC_RADIO2; + } else if(updateChannel == UpdateChannelDevelopment) + { radioID = IDC_RADIO3; - } else if(periodDays >= 1) - { - radioID = IDC_RADIO2; } else { radioID = IDC_RADIO1; } - CheckRadioButton(IDC_RADIO1, IDC_RADIO4, radioID); + CheckRadioButton(IDC_RADIO1, IDC_RADIO3, radioID); + + int32 periodDays = TrackerSettings::Instance().UpdateIntervalDays; + int ndx; + + ndx = m_CbnUpdateFrequency.AddString(_T("always")); + m_CbnUpdateFrequency.SetItemData(ndx, 0); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("daily")); + m_CbnUpdateFrequency.SetItemData(ndx, 1); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("weekly")); + m_CbnUpdateFrequency.SetItemData(ndx, 7); + if(periodDays >= 7) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("monthly")); + m_CbnUpdateFrequency.SetItemData(ndx, 30); + if(periodDays >= 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("never")); + m_CbnUpdateFrequency.SetItemData(ndx, ~(DWORD_PTR)0); + if(periodDays < 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateSendGUID ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(IDC_EDIT1, mpt::ToCString(TrackerSettings::Instance().UpdateUpdateURL.Get())); + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->SetWindowText(_T("A randomized user ID is created and transmitted alongside. This ID can only be linked to you or your computer by this very ID, which is stored solely on your computer. OpenMPT will use this information to gather usage statistics and to plan removal of support for older systems. The following information will be sent:")); + + UpdateStatistics(); + + EnableDisableDialog(); + m_SettingChangedNotifyGuard.Register(this); SettingChanged(TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()); @@ -396,6 +595,43 @@ } +void CUpdateSetupDlg::UpdateStatistics() +{ + CUpdateCheck::Settings settings; + + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + + CString updateURL; + GetDlgItemText(IDC_EDIT1, updateURL); + + settings.periodDays = updateCheckPeriod; + settings.channel = updateChannel; + settings.sendStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); + + mpt::ustring statistics; + statistics += MPT_USTRING("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + MPT_ULITERAL("\n"); + statistics += MPT_ULITERAL("\n"); + if(settings.sendStatistics) + { + if(settings.statisticsUUID.IsValid()) + { + statistics += MPT_USTRING("PUT ") + settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID) + MPT_ULITERAL("\n"); + } else + { + statistics += MPT_USTRING("POST ") + settings.apiURL + MPT_USTRING("statistics/") + MPT_ULITERAL("\n"); + } + statistics += mpt::String::Replace(mpt::ToUnicode(mpt::CharsetUTF8, CUpdateCheck::GetStatisticsDataV3(settings)), MPT_USTRING("\t"), MPT_USTRING(" ")); + statistics += MPT_ULITERAL("\n"); + } + SetDlgItemText(IDC_EDIT_STATISTICS, mpt::ToCString(mpt::String::Replace(statistics, MPT_USTRING("\n"), MPT_USTRING("\r\n")))); +} + + void CUpdateSetupDlg::SettingChanged(const SettingPath &changedPath) { if(changedPath == TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()) @@ -420,19 +656,60 @@ } +void CUpdateSetupDlg::EnableDisableDialog() +{ + + BOOL status = ((IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED) ? TRUE : FALSE); + + GetDlgItem(IDC_STATIC_UDATECHANNEL)->EnableWindow(status); + GetDlgItem(IDC_RADIO1)->EnableWindow(status); + GetDlgItem(IDC_RADIO2)->EnableWindow(status); + GetDlgItem(IDC_RADIO3)->EnableWindow(status); + + GetDlgItem(IDC_STATIC_UPDATECHECK)->EnableWindow(status); + GetDlgItem(IDC_STATIC_UPDATEFREQUENCY)->EnableWindow(status); + GetDlgItem(IDC_COMBO_UPDATEFREQUENCY)->EnableWindow(status); + GetDlgItem(IDC_BUTTON1)->EnableWindow(status); + GetDlgItem(IDC_LASTUPDATE)->EnableWindow(status); + + GetDlgItem(IDC_STATIC_UPDATEPRIVACY)->EnableWindow(status); + GetDlgItem(IDC_CHECK1)->EnableWindow(status); + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->EnableWindow(status); + GetDlgItem(IDC_EDIT_STATISTICS)->EnableWindow(status); + + // disabled features + GetDlgItem(IDC_CHECK_UPDATEENABLED)->EnableWindow(FALSE); + GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); + +} + + +void CUpdateSetupDlg::OnSettingsChanged() +{ + EnableDisableDialog(); + UpdateStatistics(); + SetModified(TRUE); +} + + void CUpdateSetupDlg::OnOK() { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(IsDlgButtonChecked(IDC_RADIO1)) updateCheckPeriod = 0; - if(IsDlgButtonChecked(IDC_RADIO2)) updateCheckPeriod = 1; - if(IsDlgButtonChecked(IDC_RADIO3)) updateCheckPeriod = 7; - if(IsDlgButtonChecked(IDC_RADIO4)) updateCheckPeriod = 31; + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + CString updateURL; GetDlgItemText(IDC_EDIT1, updateURL); - TrackerSettings::Instance().UpdateUpdateCheckPeriod = updateCheckPeriod; - TrackerSettings::Instance().UpdateUpdateURL = mpt::ToUnicode(updateURL); + if(GetDlgItem(IDC_CHECK_UPDATEENABLED)->IsWindowEnabled() != FALSE) + { + TrackerSettings::Instance().UpdateEnabled = (IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED); + } + TrackerSettings::Instance().UpdateIntervalDays = updateCheckPeriod; + TrackerSettings::Instance().UpdateChannel = updateChannel; TrackerSettings::Instance().UpdateSendGUID = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); CPropertyPage::OnOK(); @@ -452,10 +729,4 @@ } -void CUpdateSetupDlg::OnResetURL() -{ - SetDlgItemText(IDC_EDIT1, mpt::ToCString(CUpdateCheck::GetDefaultUpdateURL())); -} - - OPENMPT_NAMESPACE_END Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 10769) +++ mptrack/UpdateCheck.h (working copy) @@ -24,6 +24,13 @@ OPENMPT_NAMESPACE_BEGIN +enum UpdateChannel +{ + UpdateChannelRelease = 1, + UpdateChannelNext = 2, + UpdateChannelDevelopment = 3, +}; + class CUpdateCheck { @@ -33,7 +40,11 @@ public: - static mpt::ustring GetDefaultUpdateURL(); + static mpt::ustring GetDefaultChannelReleaseURL(); + static mpt::ustring GetDefaultChannelNextURL(); + static mpt::ustring GetDefaultChannelDevelopmentURL(); + + static mpt::ustring GetDefaultAPIURL(); int32 GetNumCurrentRunningInstances(); @@ -42,7 +53,7 @@ public: - struct Settings + struct Context { CWnd *window; UINT msgProgress; @@ -49,10 +60,20 @@ UINT msgSuccess; UINT msgFailure; bool autoUpdate; - mpt::ustring updateBaseURL; // URL where the version check should be made. + }; + + struct Settings + { + int32 periodDays; + uint32 channel; + mpt::ustring channelReleaseURL; + mpt::ustring channelNextURL; + mpt::ustring channelDevelopmentURL; + mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; bool suggestDifferentBuilds; + Settings(); }; class Error @@ -86,6 +107,14 @@ static void ShowSuccessGUI(WPARAM wparam, LPARAM lparam); static void ShowFailureGUI(WPARAM wparam, LPARAM lparam); +public: + + // v2 + static mpt::ustring GetUpdateURLV2(const Settings &settings); + + // v3 + static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 + protected: static void StartUpdateCheckAsync(bool autoUpdate); @@ -93,11 +122,12 @@ struct ThreadFunc { CUpdateCheck::Settings settings; - ThreadFunc(const CUpdateCheck::Settings &settings); + CUpdateCheck::Context context; + ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); void operator () (); }; - static void CheckForUpdate(const CUpdateCheck::Settings &settings); + static void CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); static CUpdateCheck::Result SearchUpdate(const CUpdateCheck::Settings &settings); // may throw @@ -111,17 +141,20 @@ CUpdateSetupDlg(); protected: + virtual void DoDataExchange(CDataExchange *pDX); virtual BOOL OnInitDialog(); virtual void OnOK(); virtual BOOL OnSetActive(); - afx_msg void OnSettingsChanged() { SetModified(TRUE); } + afx_msg void OnSettingsChanged(); afx_msg void OnCheckNow(); - afx_msg void OnResetURL(); virtual void SettingChanged(const SettingPath &changedPath); + void EnableDisableDialog(); + void UpdateStatistics(); DECLARE_MESSAGE_MAP() private: SettingChangedNotifyGuard m_SettingChangedNotifyGuard; + CComboBox m_CbnUpdateFrequency; }; Index: mptrack/WelcomeDialog.cpp =================================================================== --- mptrack/WelcomeDialog.cpp (revision 10769) +++ mptrack/WelcomeDialog.cpp (working copy) @@ -147,7 +147,7 @@ CDialog::OnOK(); bool runUpdates = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED; - TrackerSettings::Instance().UpdateUpdateCheckPeriod = (runUpdates ? 7 : 0); + TrackerSettings::Instance().UpdateIntervalDays = (runUpdates ? 7 : 0); if(IsDlgButtonChecked(IDC_CHECK2) != BST_UNCHECKED) { FontSetting font = TrackerSettings::Instance().patternFont; update-statistics-v5.patch (43,422 bytes)
Index: common/mptOS.cpp =================================================================== --- common/mptOS.cpp (revision 10963) +++ common/mptOS.cpp (working copy) @@ -589,6 +589,20 @@ } +std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host) +{ + std::vector<Architecture> result; + for(const auto & entry : hostArchitectureCanRun) + { + if(entry.Host == host) + { + result.push_back(entry.Process); + } + } + return result; +} + + #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS @@ -629,6 +643,18 @@ #endif // MPT_OS_WINDOWS +uint64 GetSystemMemorySize() +{ + MEMORYSTATUSEX memoryStatus; + MemsetZero(memoryStatus); + memoryStatus.dwLength = sizeof(MEMORYSTATUSEX); + if(GlobalMemoryStatusEx(&memoryStatus) == 0) + { + return 0; + } + return memoryStatus.ullTotalPhys; +} + static bool SystemIsWine(bool allowDetection = true) { #if MPT_OS_WINDOWS Index: common/mptOS.h =================================================================== --- common/mptOS.h (revision 10963) +++ common/mptOS.h (working copy) @@ -183,11 +183,15 @@ EmulationLevel HostCanRun(Architecture host, Architecture process) noexcept; +std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host); + #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS #if defined(MODPLUG_TRACKER) +uint64 GetSystemMemorySize(); + void PreventWineDetection(); bool IsOriginal(); Index: common/versionNumber.h =================================================================== --- common/versionNumber.h (revision 10963) +++ common/versionNumber.h (working copy) @@ -21,7 +21,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 28 #define VER_MINOR 00 -#define VER_MINORMINOR 37 +#define VER_MINORMINOR 38 //Numerical value of the version. #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR) Index: mptrack/Mptrack.cpp =================================================================== --- mptrack/Mptrack.cpp (revision 10963) +++ mptrack/Mptrack.cpp (working copy) @@ -1071,8 +1071,25 @@ font.size = Clamp(Util::GetDPIy(m_pMainWnd->m_hWnd) / 96 - 1, 0, 9); TrackerSettings::Instance().patternFont = font; new WelcomeDlg(m_pMainWnd); + + TrackerSettings::Instance().UpdateStatisticsConsentAsked = true; + } else { + + // ask if user wants to contribute system statistics + if(!TrackerSettings::Instance().UpdateStatisticsConsentAsked) + { + TrackerSettings::Instance().UpdateStatistics = (ConfirmAnswer::cnfYes == Reporting::Confirm( + MPT_USTRING("Do you want to contribute to OpenMPT by providing system statistics?\r\n") + + MPT_USTRING("\r\n") + + mpt::String::Replace(CUpdateCheck::GetStatisticsUserInformation(false), MPT_USTRING("\n"), MPT_USTRING("\r\n")) + MPT_USTRING("\r\n") + + MPT_USTRING("\r\n") + + mpt::format(MPT_USTRING("This option was previously %1 on your system.\r\n"))(TrackerSettings::Instance().UpdateStatistics ? MPT_USTRING("enabled") : MPT_USTRING("disabled")), + false, !TrackerSettings::Instance().UpdateStatistics.Get())); + TrackerSettings::Instance().UpdateStatisticsConsentAsked = true; + } + // Update check CUpdateCheck::DoAutoUpdateCheck(); Index: mptrack/mptrack.rc =================================================================== --- mptrack/mptrack.rc (revision 10963) +++ mptrack/mptrack.rc (working copy) @@ -244,22 +244,25 @@ CAPTION "Update" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Check for Updates",IDC_STATIC,6,6,276,66 - CONTROL "&Never",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,12,18,240,8 - CONTROL "&Daily",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,12,30,240,8 - CONTROL "&Weekly (recommended)",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,12,42,240,8 - CONTROL "&Monthly",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,12,54,240,8 - GROUPBOX "Privacy Settings",IDC_STATIC,6,78,276,54 - CONTROL "&Allow us to collect basic update statistics",IDC_CHECK1, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,90,246,12 - LTEXT "If enabled, a randomized user ID is created and transmitted with every update check. This ID can not be linked to you or your computer in any way.",IDC_STATIC,12,102,264,24 - GROUPBOX "Advanced Settings",IDC_STATIC,6,138,276,60 - LTEXT "&Update server URL:",IDC_STATIC,12,150,186,8 - EDITTEXT IDC_EDIT1,12,162,264,12,ES_AUTOHSCROLL - PUSHBUTTON "&Reset",IDC_BUTTON2,222,146,54,12 - LTEXT "Do not change this unless you are absolutely sure of what you are doing.",IDC_STATIC,12,180,264,12 - PUSHBUTTON "&Check for Updates",IDC_BUTTON1,6,204,84,18 - LTEXT "",IDC_LASTUPDATE,6,228,276,48 + CONTROL "Enable online Update &Check",IDC_CHECK_UPDATEENABLED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,6,105,10 + GROUPBOX "Update Channel",IDC_STATIC_UDATECHANNEL,6,18,276,54 + CONTROL "release: official stable released versions only (recommended)",IDC_RADIO1, + "Button",BS_AUTORADIOBUTTON,12,30,211,10 + CONTROL "next: previews of the next official stable release",IDC_RADIO2, + "Button",BS_AUTORADIOBUTTON,12,42,171,10 + CONTROL "development: bleeding-edge development versions",IDC_RADIO3, + "Button",BS_AUTORADIOBUTTON,12,54,179,10 + GROUPBOX "Check for Updates",IDC_STATIC_UPDATECHECK,6,72,276,48 + LTEXT "&Automatically check on program start:",IDC_STATIC_UPDATEFREQUENCY,12,84,126,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_UPDATEFREQUENCY,138,84,42,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Check now...",IDC_BUTTON1,216,84,60,12 + LTEXT "",IDC_LASTUPDATE,12,102,264,12 + GROUPBOX "Privacy Settings",IDC_STATIC_UPDATEPRIVACY,6,120,276,156 + CONTROL "&Allow OpenMPT to collect basic statistics about your system configuration",IDC_CHECK1, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,132,264,12 + LTEXT "",IDC_STATIC_UPDATEPRIVACYTEXT,12,144,264,36 + EDITTEXT IDC_EDIT_STATISTICS,12,180,264,90,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_CLOSEDOCUMENTS DIALOGEX 0, 0, 370, 197 @@ -374,23 +377,26 @@ PUSHBUTTON "&Cancel",IDCANCEL,138,24,50,14 END -IDD_WECLOME DIALOGEX 0, 0, 256, 137 +IDD_WECLOME DIALOGEX 0, 0, 257, 261 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Welcome to OpenMPT!" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "&OK",IDOK,198,116,50,14 + DEFPUSHBUTTON "&OK",IDOK,198,236,50,14 LTEXT "Please review the following settings before using this software:",IDC_STATIC,6,6,246,8 CONTROL "&Automatically check for new versions of OpenMPT",IDC_CHECK1, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,24,246,10 + CONTROL "Help OpenMPT development by providing basic s&tatistics",IDC_CHECK3, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,42,234,10 + LTEXT "Static",IDC_STATIC_WELCOME_STATISTICS,30,54,216,102 CONTROL "&Use a big font in the pattern editor",IDC_CHECK2, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,42,246,10 - LTEXT "&Default keyboard scheme:",IDC_STATIC,6,63,108,8 - COMBOBOX IDC_COMBO1,114,60,132,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Scan for existing VST plugins in the following location:",IDC_STATIC,6,82,172,8 - PUSHBUTTON "&Scan",IDC_BUTTON2,198,79,50,14 - EDITTEXT IDC_EDIT1,6,95,240,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - PUSHBUTTON "&More Settings",IDC_BUTTON1,6,116,60,14 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,162,246,10 + LTEXT "&Default keyboard scheme:",IDC_STATIC,6,183,108,8 + COMBOBOX IDC_COMBO1,114,180,132,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Scan for existing VST plugins in the following location:",IDC_STATIC,6,202,172,8 + PUSHBUTTON "&Scan",IDC_BUTTON2,198,199,50,14 + EDITTEXT IDC_EDIT1,6,215,240,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "&More Settings",IDC_BUTTON1,6,236,60,14 END IDD_UPDATE DIALOGEX 0, 0, 196, 138 @@ -751,9 +757,9 @@ IDD_WECLOME, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 249 + RIGHTMARGIN, 250 TOPMARGIN, 7 - BOTTOMMARGIN, 130 + BOTTOMMARGIN, 254 END IDD_UPDATE, DIALOG @@ -931,7 +937,17 @@ 0, 100, 100, 0 END +IDD_OPTIONS_UPDATE AFX_DIALOG_LAYOUT +BEGIN + 0 +END +IDD_WECLOME AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + ///////////////////////////////////////////////////////////////////////////// // // Dialog Info Index: mptrack/resource.h =================================================================== --- mptrack/resource.h (revision 10963) +++ mptrack/resource.h (working copy) @@ -975,6 +975,14 @@ #define IDC_BUTTON_TUNING_REMOVE 2501 #define IDC_STATIC_WINE_RTAUDIO 2502 #define IDC_COMBO_WINE_RTAUDIO 2503 +#define IDC_STATIC_UPDATECHECK 2504 +#define IDC_STATIC_UPDATEPRIVACY 2505 +#define IDC_STATIC_UDATECHANNEL 2506 +#define IDC_COMBO_UPDATEFREQUENCY 2507 +#define IDC_STATIC_UPDATEFREQUENCY 2508 +#define IDC_CHECK_UPDATEENABLED 2509 +#define IDC_STATIC_UPDATEPRIVACYTEXT 2510 +#define IDC_STATIC_WELCOME_STATISTICS 2511 #define ID_FILE_NEWMOD 32771 #define ID_FILE_NEWXM 32772 #define ID_FILE_NEWS3M 32773 @@ -1269,9 +1277,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 542 +#define _APS_NEXT_RESOURCE_VALUE 544 #define _APS_NEXT_COMMAND_VALUE 44646 -#define _APS_NEXT_CONTROL_VALUE 2504 +#define _APS_NEXT_CONTROL_VALUE 2512 #define _APS_NEXT_SYMED_VALUE 901 #endif #endif Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 10963) +++ mptrack/TrackerSettings.cpp (working copy) @@ -331,10 +331,19 @@ , vstHostVendorString(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorString"), "OpenMPT project") , vstHostVendorVersion(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorVersion"), Version::Current().GetRawVersion()) // Update + , UpdateEnabled(conf, MPT_USTRING("Update"), MPT_USTRING("Enabled"), true) , UpdateLastUpdateCheck(conf, MPT_USTRING("Update"), MPT_USTRING("LastUpdateCheck"), mpt::Date::Unix(time_t())) - , UpdateUpdateCheckPeriod(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) - , UpdateUpdateURL(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultUpdateURL()) - , UpdateSendGUID(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), true) + , UpdateUpdateCheckPeriod_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) + , UpdateIntervalDays(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriodDays"), 7) + , UpdateChannel(conf, MPT_USTRING("Update"), MPT_USTRING("Channel"), UpdateChannelRelease) + , UpdateUpdateURL_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelReleaseURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelNextURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) + , UpdateChannelDevelopmentURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) + , UpdateAPIURL(conf, MPT_USTRING("Update"), MPT_USTRING("APIURL"), CUpdateCheck::GetDefaultAPIURL()) + , UpdateStatisticsConsentAsked(conf, MPT_USTRING("Update"), MPT_USTRING("StatistisConsentAsked"), false) + , UpdateStatistics(conf, MPT_USTRING("Update"), MPT_USTRING("Statistis"), false) + , UpdateSendGUID_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), false) , UpdateShowUpdateHint(conf, MPT_USTRING("Update"), MPT_USTRING("ShowUpdateHint"), true) , UpdateSuggestDifferentBuildVariant(conf, MPT_USTRING("Update"), MPT_USTRING("SuggestDifferentBuildVariant"), true) , UpdateIgnoreVersion(conf, MPT_USTRING("Update"), MPT_USTRING("IgnoreVersion"), _T("")) @@ -644,6 +653,47 @@ m_dwPatternSetup &= ~0x200; } + // Update + if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,38)) + { + if(UpdateUpdateCheckPeriod_DEPRECATED <= 0) + { + UpdateEnabled = true; + UpdateIntervalDays = -1; + } else + { + UpdateEnabled = true; + UpdateIntervalDays = UpdateUpdateCheckPeriod_DEPRECATED.Get(); + } + if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://www.soal.org/openmpt/OpenMPTversionCheck.php5")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else + { + UpdateChannel = UpdateChannelDevelopment; + UpdateChannelDevelopmentURL = UpdateUpdateURL_DEPRECATED.Get(); + } + UpdateStatistics = UpdateSendGUID_DEPRECATED.Get(); + conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); + conf.Forget(UpdateUpdateURL_DEPRECATED.GetPath()); + conf.Forget(UpdateSendGUID_DEPRECATED.GetPath()); + } + // Effects #ifndef NO_EQ FixupEQ(m_EqSettings); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 10963) +++ mptrack/TrackerSettings.h (working copy) @@ -817,10 +817,19 @@ // Update + Setting<bool> UpdateEnabled; Setting<mpt::Date::Unix> UpdateLastUpdateCheck; - Setting<int32> UpdateUpdateCheckPeriod; - Setting<mpt::ustring> UpdateUpdateURL; - Setting<bool> UpdateSendGUID; + Setting<int32> UpdateUpdateCheckPeriod_DEPRECATED; + Setting<int32> UpdateIntervalDays; + Setting<uint32> UpdateChannel; + Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; + Setting<mpt::ustring> UpdateChannelReleaseURL; + Setting<mpt::ustring> UpdateChannelNextURL; + Setting<mpt::ustring> UpdateChannelDevelopmentURL; + Setting<mpt::ustring> UpdateAPIURL; + Setting<bool> UpdateStatisticsConsentAsked; + Setting<bool> UpdateStatistics; + Setting<bool> UpdateSendGUID_DEPRECATED; Setting<bool> UpdateShowUpdateHint; Setting<bool> UpdateSuggestDifferentBuildVariant; Setting<CString> UpdateIgnoreVersion; Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 10963) +++ mptrack/UpdateCheck.cpp (working copy) @@ -13,6 +13,7 @@ #include "BuildVariants.h" #include "../common/version.h" #include "../common/misc_util.h" +#include "../common/mptStringBuffer.h" #include "Mptrack.h" #include "TrackerSettings.h" // Setup dialog stuff @@ -19,6 +20,7 @@ #include "Mainfrm.h" #include "../common/mptThread.h" #include "HTTP.h" +#include "../misc/JSON.h" OPENMPT_NAMESPACE_BEGIN @@ -83,13 +85,46 @@ +mpt::ustring CUpdateCheck::GetStatisticsUserInformation(bool shortText) +{ + if(shortText) + { + return MPT_USTRING("A randomized user ID is created and transmitted alongside. This ID can only be linked to you or your computer by this very ID, which is stored solely on your computer. OpenMPT will use this information to gather usage statistics and to plan removal of support for older systems. The following information will be sent:"); + } else + { + return MPT_USTRING("") + + MPT_USTRING("When checking for updates, OpenMPT can additionally collect some basic statistical information.") + MPT_USTRING("\n") + + MPT_USTRING("A randomized user ID is created and transmitted alongside the update check. This ID can only be linked to you or your computer by this very ID, which is stored solely on your computer.") + MPT_USTRING("\n") + + MPT_USTRING("OpenMPT will use this information to gather usage statistics and to plan removal of support for older systems.") + MPT_USTRING("\n") + + MPT_USTRING("Without this statistical information, the OpenMPT developers would be blind with respect to what systems are used to run OpenMPT. This makes deciding where to focus development plain guesswork.") + MPT_USTRING("\n") + + MPT_USTRING("OpenMPT collects the following statistical data points: OpenMPT version, Windows version, type of CPU, amount of RAM, configured update check frequency of OpenMPT.") + ; + } +} -mpt::ustring CUpdateCheck::GetDefaultUpdateURL() + +mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() { return MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID"); } +mpt::ustring CUpdateCheck::GetDefaultChannelNextURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/next/$VERSION/$GUID"); +} +mpt::ustring CUpdateCheck::GetDefaultChannelDevelopmentURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID"); +} + + +mpt::ustring CUpdateCheck::GetDefaultAPIURL() +{ + return MPT_USTRING("https://update.openmpt.org/api/v3/"); +} + + std::atomic<int32> CUpdateCheck::s_InstanceCount(0); @@ -104,11 +139,15 @@ { if(isAutoUpdate) { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(updateCheckPeriod == 0) + if(!TrackerSettings::Instance().UpdateEnabled) { return; } + int updateCheckPeriod = TrackerSettings::Instance().UpdateIntervalDays; + if(updateCheckPeriod < 0) + { + return; + } // Do we actually need to run the update check right now? const time_t now = time(nullptr); if(difftime(now, TrackerSettings::Instance().UpdateLastUpdateCheck.Get()) < (double)(updateCheckPeriod * 86400)) @@ -121,7 +160,7 @@ { TrackerSettings::Instance().UpdateShowUpdateHint = false; CString msg; - msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateUpdateCheckPeriod.Get()); + msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateIntervalDays.Get()); if(Reporting::Confirm(msg, _T("OpenMPT Internet Update")) == cnfNo) { TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(now); @@ -128,6 +167,15 @@ return; } } + } else + { + if(!TrackerSettings::Instance().UpdateEnabled) + { + if(Reporting::Confirm(_T("Update Check is disabled. Do you want to check anyway?"), _T("OpenMPT Internet Update")) != cnfYes) + { + return; + } + } } TrackerSettings::Instance().UpdateShowUpdateHint = false; @@ -137,22 +185,33 @@ return; } - CUpdateCheck::Settings settings; - settings.window = CMainFrame::GetMainFrame(); - settings.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; - settings.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; - settings.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; - settings.autoUpdate = isAutoUpdate; - settings.updateBaseURL = TrackerSettings::Instance().UpdateUpdateURL; - settings.sendStatistics = TrackerSettings::Instance().UpdateSendGUID; - settings.statisticsUUID = TrackerSettings::Instance().VersionInstallGUID; - settings.suggestDifferentBuilds = TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant; - std::thread(CUpdateCheck::ThreadFunc(settings)).detach(); + CUpdateCheck::Context context; + context.window = CMainFrame::GetMainFrame(); + context.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; + context.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; + context.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; + context.autoUpdate = isAutoUpdate; + std::thread(CUpdateCheck::ThreadFunc(CUpdateCheck::Settings(), context)).detach(); } -CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings) +CUpdateCheck::Settings::Settings() + : periodDays(TrackerSettings::Instance().UpdateIntervalDays) + , channel(TrackerSettings::Instance().UpdateChannel) + , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) + , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) + , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) + , apiURL(TrackerSettings::Instance().UpdateAPIURL) + , sendStatistics(TrackerSettings::Instance().UpdateStatistics) + , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) + , suggestDifferentBuilds(TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant) +{ +} + + +CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) : settings(settings) + , context(context) { return; } @@ -160,27 +219,103 @@ void CUpdateCheck::ThreadFunc::operator () () { - mpt::SetCurrentThreadPriority(settings.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); - CUpdateCheck::CheckForUpdate(settings); + mpt::SetCurrentThreadPriority(context.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); + CUpdateCheck::CheckForUpdate(settings, context); } -// Run update check (independent thread) -CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +std::string CUpdateCheck::GetStatisticsDataV3(const Settings &settings) { - - HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + JSON::value j; + j["OpenMPT"]["Version"] = mpt::ufmt::val(Version::Current()); + j["OpenMPT"]["BuildVariant"] = BuildVariants().GuessCurrentBuildName(); + j["OpenMPT"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetProcessArchitecture()); + j["Update"]["PeriodDays"] = settings.periodDays; + j["System"]["Windows"]["Version"]["Name"] = mpt::Windows::Version::Current().GetName(); + j["System"]["Windows"]["Version"]["Major"] = mpt::Windows::Version::Current().GetSystem().Major; + j["System"]["Windows"]["Version"]["Minor"] = mpt::Windows::Version::Current().GetSystem().Minor; + j["System"]["Windows"]["ServicePack"]["Major"] = mpt::Windows::Version::Current().GetServicePack().Major; + j["System"]["Windows"]["ServicePack"]["Minor"] = mpt::Windows::Version::Current().GetServicePack().Minor; + j["System"]["Windows"]["Build"] = mpt::Windows::Version::Current().GetBuild(); + j["System"]["Windows"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetHostArchitecture()); + j["System"]["Windows"]["IsWine"] = mpt::Windows::IsWine(); + std::vector<mpt::Windows::Architecture> architectures = mpt::Windows::GetSupportedProcessArchitectures(mpt::Windows::GetHostArchitecture()); + for(const auto & arch : architectures) + { + j["System"]["Windows"]["ProcessArchitectures"][mpt::ToCharset(mpt::CharsetUTF8, mpt::Windows::Name(arch))] = true; + } + j["System"]["Memory"] = mpt::Windows::GetSystemMemorySize() / 1024 / 1024; // MB + if(mpt::Windows::IsWine()) + { + mpt::Wine::VersionContext v; + j["System"]["Windows"]["Wine"]["Version"]["Raw"] = v.RawVersion(); + if(v.Version().IsValid()) + { + j["System"]["Windows"]["Wine"]["Version"]["Major"] = v.Version().GetMajor(); + j["System"]["Windows"]["Wine"]["Version"]["Minor"] = v.Version().GetMinor(); + j["System"]["Windows"]["Wine"]["Version"]["Update"] = v.Version().GetUpdate(); + } + j["System"]["Windows"]["Wine"]["HostSysName"] = v.RawHostSysName(); + } + #ifdef ENABLE_ASM + j["System"]["Processor"]["Vendor"] = std::string(mpt::String::ReadAutoBuf(ProcVendorID)); + j["System"]["Processor"]["Brand"] = std::string(mpt::String::ReadAutoBuf(ProcBrandID)); + j["System"]["Processor"]["Id"]["Family"] = ProcFamily; + j["System"]["Processor"]["Id"]["Model"] = ProcModel; + j["System"]["Processor"]["Id"]["Stepping"] = ProcStepping; + j["System"]["Processor"]["Features"]["lm"] = ((GetRealProcSupport() & PROCSUPPORT_LM) ? true : false); + j["System"]["Processor"]["Features"]["cmov"] = ((GetRealProcSupport() & PROCSUPPORT_CMOV) ? true : false); + j["System"]["Processor"]["Features"]["mmx"] = ((GetRealProcSupport() & PROCSUPPORT_MMX) ? true : false); + j["System"]["Processor"]["Features"]["mmxext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_MMXEXT) ? true : false); + j["System"]["Processor"]["Features"]["3dnow"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOW) ? true : false); + j["System"]["Processor"]["Features"]["3dnowext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOWEXT) ? true : false); + j["System"]["Processor"]["Features"]["sse"] = ((GetRealProcSupport() & PROCSUPPORT_SSE) ? true : false); + j["System"]["Processor"]["Features"]["sse2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE2) ? true : false); + j["System"]["Processor"]["Features"]["sse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSE3) ? true : false); + j["System"]["Processor"]["Features"]["ssse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSSE3) ? true : false); + j["System"]["Processor"]["Features"]["sse4_1"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_1) ? true : false); + j["System"]["Processor"]["Features"]["sse4_2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_2) ? true : false); + #endif + return j.dump(1, '\t'); +} - mpt::ustring updateURL = settings.updateBaseURL; - if(updateURL.empty()) + +mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) +{ + mpt::ustring updateURL; + if(settings.channel == UpdateChannelRelease) { - updateURL = GetDefaultUpdateURL(); + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } + } else if(settings.channel == UpdateChannelNext) + { + updateURL = settings.channelNextURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelNextURL(); + } + } else if(settings.channel == UpdateChannelDevelopment) + { + updateURL = settings.channelDevelopmentURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelDevelopmentURL(); + } + } else + { + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } } if(updateURL.find(MPT_USTRING("://")) == mpt::ustring::npos) { updateURL = MPT_USTRING("https://") + updateURL; } - // Build update URL updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$VERSION"), mpt::uformat(MPT_USTRING("%1-%2-%3")) ( Version::Current() @@ -188,15 +323,44 @@ , settings.sendStatistics ? mpt::Windows::Version::Current().GetNameShort() : MPT_USTRING("unknown") )); updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : MPT_USTRING("anonymous")); + return updateURL; +} + +// Run update check (independent thread) +CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +{ + + HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + // Establish a connection. HTTP::Request request; - request.SetURI(ParseURI(updateURL)); + request.SetURI(ParseURI(GetUpdateURLV2(settings))); request.method = HTTP::Method::Get; request.flags = HTTP::NoCache; HTTP::Result resultHTTP = internet(request.InsecureTLSDowngradeWindowsXP()); + if(settings.sendStatistics) + { + HTTP::Request requestStatistics; + if(settings.statisticsUUID.IsValid()) + { + requestStatistics.SetURI(ParseURI(settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID))); + requestStatistics.method = HTTP::Method::Put; + } else + { + requestStatistics.SetURI(ParseURI(settings.apiURL + MPT_USTRING("statistics/"))); + requestStatistics.method = HTTP::Method::Post; + } + requestStatistics.dataMimeType = HTTP::MimeType::JSON(); + requestStatistics.acceptMimeTypes = HTTP::MimeTypes::JSON(); + std::string jsondata = GetStatisticsDataV3(settings); + MPT_LOG(LogInformation, "Update", mpt::ToUnicode(mpt::CharsetUTF8, jsondata)); + requestStatistics.data = mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(jsondata)); + internet(requestStatistics.InsecureTLSDowngradeWindowsXP()); + } + // Retrieve HTTP status code. if(resultHTTP.Status >= 400) { @@ -244,12 +408,12 @@ } -void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings) +void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) { // �ncremented before starting the thread MPT_ASSERT(s_InstanceCount.load() >= 1); CUpdateCheck::Result result; - settings.window->SendMessage(settings.msgProgress, settings.autoUpdate ? 1 : 0, s_InstanceCount.load()); + context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, s_InstanceCount.load()); try { try @@ -264,12 +428,12 @@ } } catch(const CUpdateCheck::Error &e) { - settings.window->SendMessage(settings.msgFailure, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); + context.window->SendMessage(context.msgFailure, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); return; } - settings.window->SendMessage(settings.msgSuccess, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); + context.window->SendMessage(context.msgSuccess, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); } @@ -347,14 +511,13 @@ // CUpdateSetupDlg BEGIN_MESSAGE_MAP(CUpdateSetupDlg, CPropertyPage) - ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) - ON_COMMAND(IDC_BUTTON2, &CUpdateSetupDlg::OnResetURL) - ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO4, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) - ON_EN_CHANGE(IDC_EDIT1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK_UPDATEENABLED, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) + ON_CBN_SELCHANGE(IDC_COMBO_UPDATEFREQUENCY, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) END_MESSAGE_MAP() @@ -366,29 +529,82 @@ } +void CUpdateSetupDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO_UPDATEFREQUENCY, m_CbnUpdateFrequency); +} + + BOOL CUpdateSetupDlg::OnInitDialog() { CPropertyPage::OnInitDialog(); + CheckDlgButton(IDC_CHECK_UPDATEENABLED, TrackerSettings::Instance().UpdateEnabled ? BST_CHECKED : BST_UNCHECKED); + int radioID = 0; - int periodDays = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(periodDays >= 30) + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(updateChannel == UpdateChannelRelease) { - radioID = IDC_RADIO4; - } else if(periodDays >= 7) + radioID = IDC_RADIO1; + } else if(updateChannel == UpdateChannelNext) { + radioID = IDC_RADIO2; + } else if(updateChannel == UpdateChannelDevelopment) + { radioID = IDC_RADIO3; - } else if(periodDays >= 1) - { - radioID = IDC_RADIO2; } else { radioID = IDC_RADIO1; } - CheckRadioButton(IDC_RADIO1, IDC_RADIO4, radioID); - CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateSendGUID ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(IDC_EDIT1, mpt::ToCString(TrackerSettings::Instance().UpdateUpdateURL.Get())); + CheckRadioButton(IDC_RADIO1, IDC_RADIO3, radioID); + int32 periodDays = TrackerSettings::Instance().UpdateIntervalDays; + int ndx; + + ndx = m_CbnUpdateFrequency.AddString(_T("always")); + m_CbnUpdateFrequency.SetItemData(ndx, 0); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("daily")); + m_CbnUpdateFrequency.SetItemData(ndx, 1); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("weekly")); + m_CbnUpdateFrequency.SetItemData(ndx, 7); + if(periodDays >= 7) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("monthly")); + m_CbnUpdateFrequency.SetItemData(ndx, 30); + if(periodDays >= 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("never")); + m_CbnUpdateFrequency.SetItemData(ndx, ~(DWORD_PTR)0); + if(periodDays < 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateStatistics ? BST_CHECKED : BST_UNCHECKED); + + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->SetWindowText(mpt::ToCString(CUpdateCheck::GetStatisticsUserInformation(true))); + + UpdateStatistics(); + + EnableDisableDialog(); + m_SettingChangedNotifyGuard.Register(this); SettingChanged(TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()); @@ -396,6 +612,43 @@ } +void CUpdateSetupDlg::UpdateStatistics() +{ + CUpdateCheck::Settings settings; + + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + + CString updateURL; + GetDlgItemText(IDC_EDIT1, updateURL); + + settings.periodDays = updateCheckPeriod; + settings.channel = updateChannel; + settings.sendStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); + + mpt::ustring statistics; + statistics += MPT_USTRING("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + MPT_ULITERAL("\n"); + statistics += MPT_ULITERAL("\n"); + if(settings.sendStatistics) + { + if(settings.statisticsUUID.IsValid()) + { + statistics += MPT_USTRING("PUT ") + settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID) + MPT_ULITERAL("\n"); + } else + { + statistics += MPT_USTRING("POST ") + settings.apiURL + MPT_USTRING("statistics/") + MPT_ULITERAL("\n"); + } + statistics += mpt::String::Replace(mpt::ToUnicode(mpt::CharsetUTF8, CUpdateCheck::GetStatisticsDataV3(settings)), MPT_USTRING("\t"), MPT_USTRING(" ")); + statistics += MPT_ULITERAL("\n"); + } + SetDlgItemText(IDC_EDIT_STATISTICS, mpt::ToCString(mpt::String::Replace(statistics, MPT_USTRING("\n"), MPT_USTRING("\r\n")))); +} + + void CUpdateSetupDlg::SettingChanged(const SettingPath &changedPath) { if(changedPath == TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()) @@ -420,20 +673,61 @@ } +void CUpdateSetupDlg::EnableDisableDialog() +{ + + BOOL status = ((IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED) ? TRUE : FALSE); + + GetDlgItem(IDC_STATIC_UDATECHANNEL)->EnableWindow(status); + GetDlgItem(IDC_RADIO1)->EnableWindow(status); + GetDlgItem(IDC_RADIO2)->EnableWindow(status); + GetDlgItem(IDC_RADIO3)->EnableWindow(status); + + GetDlgItem(IDC_STATIC_UPDATECHECK)->EnableWindow(status); + GetDlgItem(IDC_STATIC_UPDATEFREQUENCY)->EnableWindow(status); + GetDlgItem(IDC_COMBO_UPDATEFREQUENCY)->EnableWindow(status); + GetDlgItem(IDC_BUTTON1)->EnableWindow(status); + GetDlgItem(IDC_LASTUPDATE)->EnableWindow(status); + + GetDlgItem(IDC_STATIC_UPDATEPRIVACY)->EnableWindow(status); + GetDlgItem(IDC_CHECK1)->EnableWindow(status); + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->EnableWindow(status); + GetDlgItem(IDC_EDIT_STATISTICS)->EnableWindow(status); + + // disabled features + GetDlgItem(IDC_CHECK_UPDATEENABLED)->EnableWindow(FALSE); + GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); + +} + + +void CUpdateSetupDlg::OnSettingsChanged() +{ + EnableDisableDialog(); + UpdateStatistics(); + SetModified(TRUE); +} + + void CUpdateSetupDlg::OnOK() { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(IsDlgButtonChecked(IDC_RADIO1)) updateCheckPeriod = 0; - if(IsDlgButtonChecked(IDC_RADIO2)) updateCheckPeriod = 1; - if(IsDlgButtonChecked(IDC_RADIO3)) updateCheckPeriod = 7; - if(IsDlgButtonChecked(IDC_RADIO4)) updateCheckPeriod = 31; + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + CString updateURL; GetDlgItemText(IDC_EDIT1, updateURL); - TrackerSettings::Instance().UpdateUpdateCheckPeriod = updateCheckPeriod; - TrackerSettings::Instance().UpdateUpdateURL = mpt::ToUnicode(updateURL); - TrackerSettings::Instance().UpdateSendGUID = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); + if(GetDlgItem(IDC_CHECK_UPDATEENABLED)->IsWindowEnabled() != FALSE) + { + TrackerSettings::Instance().UpdateEnabled = (IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED); + } + TrackerSettings::Instance().UpdateIntervalDays = updateCheckPeriod; + TrackerSettings::Instance().UpdateChannel = updateChannel; + TrackerSettings::Instance().UpdateStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); CPropertyPage::OnOK(); } @@ -452,10 +746,4 @@ } -void CUpdateSetupDlg::OnResetURL() -{ - SetDlgItemText(IDC_EDIT1, mpt::ToCString(CUpdateCheck::GetDefaultUpdateURL())); -} - - OPENMPT_NAMESPACE_END Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 10963) +++ mptrack/UpdateCheck.h (working copy) @@ -24,6 +24,13 @@ OPENMPT_NAMESPACE_BEGIN +enum UpdateChannel +{ + UpdateChannelRelease = 1, + UpdateChannelNext = 2, + UpdateChannelDevelopment = 3, +}; + class CUpdateCheck { @@ -33,7 +40,13 @@ public: - static mpt::ustring GetDefaultUpdateURL(); + static mpt::ustring GetStatisticsUserInformation(bool shortText); + + static mpt::ustring GetDefaultChannelReleaseURL(); + static mpt::ustring GetDefaultChannelNextURL(); + static mpt::ustring GetDefaultChannelDevelopmentURL(); + + static mpt::ustring GetDefaultAPIURL(); int32 GetNumCurrentRunningInstances(); @@ -42,7 +55,7 @@ public: - struct Settings + struct Context { CWnd *window; UINT msgProgress; @@ -49,10 +62,20 @@ UINT msgSuccess; UINT msgFailure; bool autoUpdate; - mpt::ustring updateBaseURL; // URL where the version check should be made. + }; + + struct Settings + { + int32 periodDays; + uint32 channel; + mpt::ustring channelReleaseURL; + mpt::ustring channelNextURL; + mpt::ustring channelDevelopmentURL; + mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; bool suggestDifferentBuilds; + Settings(); }; class Error @@ -86,6 +109,14 @@ static void ShowSuccessGUI(WPARAM wparam, LPARAM lparam); static void ShowFailureGUI(WPARAM wparam, LPARAM lparam); +public: + + // v2 + static mpt::ustring GetUpdateURLV2(const Settings &settings); + + // v3 + static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 + protected: static void StartUpdateCheckAsync(bool autoUpdate); @@ -93,11 +124,12 @@ struct ThreadFunc { CUpdateCheck::Settings settings; - ThreadFunc(const CUpdateCheck::Settings &settings); + CUpdateCheck::Context context; + ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); void operator () (); }; - static void CheckForUpdate(const CUpdateCheck::Settings &settings); + static void CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); static CUpdateCheck::Result SearchUpdate(const CUpdateCheck::Settings &settings); // may throw @@ -111,17 +143,20 @@ CUpdateSetupDlg(); protected: + virtual void DoDataExchange(CDataExchange *pDX); virtual BOOL OnInitDialog(); virtual void OnOK(); virtual BOOL OnSetActive(); - afx_msg void OnSettingsChanged() { SetModified(TRUE); } + afx_msg void OnSettingsChanged(); afx_msg void OnCheckNow(); - afx_msg void OnResetURL(); virtual void SettingChanged(const SettingPath &changedPath); + void EnableDisableDialog(); + void UpdateStatistics(); DECLARE_MESSAGE_MAP() private: SettingChangedNotifyGuard m_SettingChangedNotifyGuard; + CComboBox m_CbnUpdateFrequency; }; Index: mptrack/WelcomeDialog.cpp =================================================================== --- mptrack/WelcomeDialog.cpp (revision 10963) +++ mptrack/WelcomeDialog.cpp (working copy) @@ -119,6 +119,8 @@ combo->SetItemDataPtr(combo->AddString(_T("FastTracker 2")), (void*)("US_mpt-ft2_classic")); CheckDlgButton(IDC_CHECK1, BST_CHECKED); + CheckDlgButton(IDC_CHECK3, BST_UNCHECKED); + GetDlgItem(IDC_STATIC_WELCOME_STATISTICS)->SetWindowText(mpt::ToCString(mpt::String::Replace(CUpdateCheck::GetStatisticsUserInformation(false), MPT_USTRING("\n"), MPT_USTRING(" ")))); CheckDlgButton(IDC_CHECK2, (TrackerSettings::Instance().patternFont.Get().name == PATTERNFONT_LARGE) ? BST_CHECKED : BST_UNCHECKED); ShowWindow(SW_SHOW); @@ -147,7 +149,8 @@ CDialog::OnOK(); bool runUpdates = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED; - TrackerSettings::Instance().UpdateUpdateCheckPeriod = (runUpdates ? 7 : 0); + TrackerSettings::Instance().UpdateIntervalDays = (runUpdates ? 7 : 0); + TrackerSettings::Instance().UpdateStatistics = (IsDlgButtonChecked(IDC_CHECK3) != BST_UNCHECKED); if(IsDlgButtonChecked(IDC_CHECK2) != BST_UNCHECKED) { FontSetting font = TrackerSettings::Instance().patternFont; update-statistics-v7.patch (43,972 bytes)
Index: common/mptOS.cpp =================================================================== --- common/mptOS.cpp (revision 10965) +++ common/mptOS.cpp (working copy) @@ -589,6 +589,20 @@ } +std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host) +{ + std::vector<Architecture> result; + for(const auto & entry : hostArchitectureCanRun) + { + if(entry.Host == host) + { + result.push_back(entry.Process); + } + } + return result; +} + + #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS @@ -629,6 +643,18 @@ #endif // MPT_OS_WINDOWS +uint64 GetSystemMemorySize() +{ + MEMORYSTATUSEX memoryStatus; + MemsetZero(memoryStatus); + memoryStatus.dwLength = sizeof(MEMORYSTATUSEX); + if(GlobalMemoryStatusEx(&memoryStatus) == 0) + { + return 0; + } + return memoryStatus.ullTotalPhys; +} + static bool SystemIsWine(bool allowDetection = true) { #if MPT_OS_WINDOWS Index: common/mptOS.h =================================================================== --- common/mptOS.h (revision 10965) +++ common/mptOS.h (working copy) @@ -183,11 +183,15 @@ EmulationLevel HostCanRun(Architecture host, Architecture process) noexcept; +std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host); + #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS #if defined(MODPLUG_TRACKER) +uint64 GetSystemMemorySize(); + void PreventWineDetection(); bool IsOriginal(); Index: common/versionNumber.h =================================================================== --- common/versionNumber.h (revision 10965) +++ common/versionNumber.h (working copy) @@ -21,7 +21,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 28 #define VER_MINOR 00 -#define VER_MINORMINOR 38 +#define VER_MINORMINOR 39 //Numerical value of the version. #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR) Index: mptrack/Mptrack.cpp =================================================================== --- mptrack/Mptrack.cpp (revision 10965) +++ mptrack/Mptrack.cpp (working copy) @@ -1071,8 +1071,25 @@ font.size = Clamp(Util::GetDPIy(m_pMainWnd->m_hWnd) / 96 - 1, 0, 9); TrackerSettings::Instance().patternFont = font; new WelcomeDlg(m_pMainWnd); + + TrackerSettings::Instance().UpdateStatisticsConsentAsked = true; + } else { + + // ask if user wants to contribute system statistics + if(!TrackerSettings::Instance().UpdateStatisticsConsentAsked) + { + TrackerSettings::Instance().UpdateStatistics = (ConfirmAnswer::cnfYes == Reporting::Confirm( + MPT_USTRING("Do you want to contribute to OpenMPT by providing system statistics?\r\n") + + MPT_USTRING("\r\n") + + mpt::String::Replace(CUpdateCheck::GetStatisticsUserInformation(false), MPT_USTRING("\n"), MPT_USTRING("\r\n")) + MPT_USTRING("\r\n") + + MPT_USTRING("\r\n") + + mpt::format(MPT_USTRING("This option was previously %1 on your system.\r\n"))(TrackerSettings::Instance().UpdateStatistics ? MPT_USTRING("enabled") : MPT_USTRING("disabled")), + false, !TrackerSettings::Instance().UpdateStatistics.Get())); + TrackerSettings::Instance().UpdateStatisticsConsentAsked = true; + } + // Update check CUpdateCheck::DoAutoUpdateCheck(); Index: mptrack/mptrack.rc =================================================================== --- mptrack/mptrack.rc (revision 10965) +++ mptrack/mptrack.rc (working copy) @@ -244,22 +244,25 @@ CAPTION "Update" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Check for Updates",IDC_STATIC,6,6,276,66 - CONTROL "&Never",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,12,18,240,8 - CONTROL "&Daily",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,12,30,240,8 - CONTROL "&Weekly (recommended)",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,12,42,240,8 - CONTROL "&Monthly",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,12,54,240,8 - GROUPBOX "Privacy Settings",IDC_STATIC,6,78,276,54 - CONTROL "&Allow us to collect basic update statistics",IDC_CHECK1, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,90,246,12 - LTEXT "If enabled, a randomized user ID is created and transmitted with every update check. This ID can not be linked to you or your computer in any way.",IDC_STATIC,12,102,264,24 - GROUPBOX "Advanced Settings",IDC_STATIC,6,138,276,60 - LTEXT "&Update server URL:",IDC_STATIC,12,150,186,8 - EDITTEXT IDC_EDIT1,12,162,264,12,ES_AUTOHSCROLL - PUSHBUTTON "&Reset",IDC_BUTTON2,222,146,54,12 - LTEXT "Do not change this unless you are absolutely sure of what you are doing.",IDC_STATIC,12,180,264,12 - PUSHBUTTON "&Check for Updates",IDC_BUTTON1,6,204,84,18 - LTEXT "",IDC_LASTUPDATE,6,228,276,48 + CONTROL "Enable online Update &Check",IDC_CHECK_UPDATEENABLED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,6,105,10 + GROUPBOX "Update Channel",IDC_STATIC_UDATECHANNEL,6,18,276,54 + CONTROL "release: official stable released versions only (recommended)",IDC_RADIO1, + "Button",BS_AUTORADIOBUTTON,12,30,211,10 + CONTROL "next: previews of the next official stable release",IDC_RADIO2, + "Button",BS_AUTORADIOBUTTON,12,42,171,10 + CONTROL "development: bleeding-edge development versions",IDC_RADIO3, + "Button",BS_AUTORADIOBUTTON,12,54,179,10 + GROUPBOX "Check for Updates",IDC_STATIC_UPDATECHECK,6,72,276,48 + LTEXT "&Automatically check on program start:",IDC_STATIC_UPDATEFREQUENCY,12,84,126,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_UPDATEFREQUENCY,138,84,42,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Check now...",IDC_BUTTON1,216,84,60,12 + LTEXT "",IDC_LASTUPDATE,12,102,264,12 + GROUPBOX "Privacy Settings",IDC_STATIC_UPDATEPRIVACY,6,120,276,156 + CONTROL "&Allow OpenMPT to collect basic statistics about your system configuration",IDC_CHECK1, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,132,264,12 + LTEXT "",IDC_STATIC_UPDATEPRIVACYTEXT,12,144,264,36 + EDITTEXT IDC_EDIT_STATISTICS,12,180,264,90,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_CLOSEDOCUMENTS DIALOGEX 0, 0, 370, 197 @@ -374,23 +377,26 @@ PUSHBUTTON "&Cancel",IDCANCEL,138,24,50,14 END -IDD_WECLOME DIALOGEX 0, 0, 256, 137 +IDD_WECLOME DIALOGEX 0, 0, 257, 261 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Welcome to OpenMPT!" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "&OK",IDOK,198,116,50,14 + DEFPUSHBUTTON "&OK",IDOK,198,236,50,14 LTEXT "Please review the following settings before using this software:",IDC_STATIC,6,6,246,8 CONTROL "&Automatically check for new versions of OpenMPT",IDC_CHECK1, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,24,246,10 + CONTROL "Help OpenMPT development by providing basic s&tatistics",IDC_CHECK3, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,42,234,10 + LTEXT "Static",IDC_STATIC_WELCOME_STATISTICS,30,54,216,102 CONTROL "&Use a big font in the pattern editor",IDC_CHECK2, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,42,246,10 - LTEXT "&Default keyboard scheme:",IDC_STATIC,6,63,108,8 - COMBOBOX IDC_COMBO1,114,60,132,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Scan for existing VST plugins in the following location:",IDC_STATIC,6,82,172,8 - PUSHBUTTON "&Scan",IDC_BUTTON2,198,79,50,14 - EDITTEXT IDC_EDIT1,6,95,240,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - PUSHBUTTON "&More Settings",IDC_BUTTON1,6,116,60,14 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,162,246,10 + LTEXT "&Default keyboard scheme:",IDC_STATIC,6,183,108,8 + COMBOBOX IDC_COMBO1,114,180,132,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Scan for existing VST plugins in the following location:",IDC_STATIC,6,202,172,8 + PUSHBUTTON "&Scan",IDC_BUTTON2,198,199,50,14 + EDITTEXT IDC_EDIT1,6,215,240,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "&More Settings",IDC_BUTTON1,6,236,60,14 END IDD_UPDATE DIALOGEX 0, 0, 196, 138 @@ -751,9 +757,9 @@ IDD_WECLOME, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 249 + RIGHTMARGIN, 250 TOPMARGIN, 7 - BOTTOMMARGIN, 130 + BOTTOMMARGIN, 254 END IDD_UPDATE, DIALOG @@ -931,7 +937,17 @@ 0, 100, 100, 0 END +IDD_OPTIONS_UPDATE AFX_DIALOG_LAYOUT +BEGIN + 0 +END +IDD_WECLOME AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + ///////////////////////////////////////////////////////////////////////////// // // Dialog Info Index: mptrack/resource.h =================================================================== --- mptrack/resource.h (revision 10965) +++ mptrack/resource.h (working copy) @@ -975,6 +975,14 @@ #define IDC_BUTTON_TUNING_REMOVE 2501 #define IDC_STATIC_WINE_RTAUDIO 2502 #define IDC_COMBO_WINE_RTAUDIO 2503 +#define IDC_STATIC_UPDATECHECK 2504 +#define IDC_STATIC_UPDATEPRIVACY 2505 +#define IDC_STATIC_UDATECHANNEL 2506 +#define IDC_COMBO_UPDATEFREQUENCY 2507 +#define IDC_STATIC_UPDATEFREQUENCY 2508 +#define IDC_CHECK_UPDATEENABLED 2509 +#define IDC_STATIC_UPDATEPRIVACYTEXT 2510 +#define IDC_STATIC_WELCOME_STATISTICS 2511 #define ID_FILE_NEWMOD 32771 #define ID_FILE_NEWXM 32772 #define ID_FILE_NEWS3M 32773 @@ -1269,9 +1277,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 542 +#define _APS_NEXT_RESOURCE_VALUE 544 #define _APS_NEXT_COMMAND_VALUE 44646 -#define _APS_NEXT_CONTROL_VALUE 2504 +#define _APS_NEXT_CONTROL_VALUE 2512 #define _APS_NEXT_SYMED_VALUE 901 #endif #endif Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 10965) +++ mptrack/TrackerSettings.cpp (working copy) @@ -332,10 +332,19 @@ , vstHostVendorString(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorString"), "OpenMPT project") , vstHostVendorVersion(conf, MPT_USTRING("VST Plugins"), MPT_USTRING("HostVendorVersion"), Version::Current().GetRawVersion()) // Update + , UpdateEnabled(conf, MPT_USTRING("Update"), MPT_USTRING("Enabled"), true) , UpdateLastUpdateCheck(conf, MPT_USTRING("Update"), MPT_USTRING("LastUpdateCheck"), mpt::Date::Unix(time_t())) - , UpdateUpdateCheckPeriod(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) - , UpdateUpdateURL(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultUpdateURL()) - , UpdateSendGUID(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), true) + , UpdateUpdateCheckPeriod_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriod"), 7) + , UpdateIntervalDays(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateCheckPeriodDays"), 7) + , UpdateChannel(conf, MPT_USTRING("Update"), MPT_USTRING("Channel"), UpdateChannelRelease) + , UpdateUpdateURL_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelReleaseURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) + , UpdateChannelNextURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) + , UpdateChannelDevelopmentURL(conf, MPT_USTRING("Update"), MPT_USTRING("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) + , UpdateAPIURL(conf, MPT_USTRING("Update"), MPT_USTRING("APIURL"), CUpdateCheck::GetDefaultAPIURL()) + , UpdateStatisticsConsentAsked(conf, MPT_USTRING("Update"), MPT_USTRING("StatistisConsentAsked"), false) + , UpdateStatistics(conf, MPT_USTRING("Update"), MPT_USTRING("Statistis"), false) + , UpdateSendGUID_DEPRECATED(conf, MPT_USTRING("Update"), MPT_USTRING("SendGUID"), false) , UpdateShowUpdateHint(conf, MPT_USTRING("Update"), MPT_USTRING("ShowUpdateHint"), true) , UpdateSuggestDifferentBuildVariant(conf, MPT_USTRING("Update"), MPT_USTRING("SuggestDifferentBuildVariant"), true) , UpdateIgnoreVersion(conf, MPT_USTRING("Update"), MPT_USTRING("IgnoreVersion"), _T("")) @@ -645,6 +654,47 @@ m_dwPatternSetup &= ~0x200; } + // Update + if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,39)) + { + if(UpdateUpdateCheckPeriod_DEPRECATED <= 0) + { + UpdateEnabled = true; + UpdateIntervalDays = -1; + } else + { + UpdateEnabled = true; + UpdateIntervalDays = UpdateUpdateCheckPeriod_DEPRECATED.Get(); + } + if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://www.soal.org/openmpt/OpenMPTversionCheck.php5")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelRelease; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("http://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else if(UpdateUpdateURL_DEPRECATED.Get() == MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID")) + { + UpdateChannel = UpdateChannelDevelopment; + } else + { + UpdateChannel = UpdateChannelDevelopment; + UpdateChannelDevelopmentURL = UpdateUpdateURL_DEPRECATED.Get(); + } + UpdateStatistics = UpdateSendGUID_DEPRECATED.Get(); + conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); + conf.Forget(UpdateUpdateURL_DEPRECATED.GetPath()); + conf.Forget(UpdateSendGUID_DEPRECATED.GetPath()); + } + // Effects #ifndef NO_EQ FixupEQ(m_EqSettings); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 10965) +++ mptrack/TrackerSettings.h (working copy) @@ -818,10 +818,19 @@ // Update + Setting<bool> UpdateEnabled; Setting<mpt::Date::Unix> UpdateLastUpdateCheck; - Setting<int32> UpdateUpdateCheckPeriod; - Setting<mpt::ustring> UpdateUpdateURL; - Setting<bool> UpdateSendGUID; + Setting<int32> UpdateUpdateCheckPeriod_DEPRECATED; + Setting<int32> UpdateIntervalDays; + Setting<uint32> UpdateChannel; + Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; + Setting<mpt::ustring> UpdateChannelReleaseURL; + Setting<mpt::ustring> UpdateChannelNextURL; + Setting<mpt::ustring> UpdateChannelDevelopmentURL; + Setting<mpt::ustring> UpdateAPIURL; + Setting<bool> UpdateStatisticsConsentAsked; + Setting<bool> UpdateStatistics; + Setting<bool> UpdateSendGUID_DEPRECATED; Setting<bool> UpdateShowUpdateHint; Setting<bool> UpdateSuggestDifferentBuildVariant; Setting<CString> UpdateIgnoreVersion; Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 10965) +++ mptrack/UpdateCheck.cpp (working copy) @@ -13,6 +13,7 @@ #include "BuildVariants.h" #include "../common/version.h" #include "../common/misc_util.h" +#include "../common/mptStringBuffer.h" #include "Mptrack.h" #include "TrackerSettings.h" // Setup dialog stuff @@ -19,6 +20,7 @@ #include "Mainfrm.h" #include "../common/mptThread.h" #include "HTTP.h" +#include "../misc/JSON.h" OPENMPT_NAMESPACE_BEGIN @@ -83,13 +85,46 @@ +mpt::ustring CUpdateCheck::GetStatisticsUserInformation(bool shortText) +{ + if(shortText) + { + return MPT_USTRING("A randomized user ID is created and transmitted alongside. This ID can only be linked to you or your computer by this very ID, which is stored solely on your computer. OpenMPT will use this information to gather usage statistics and to plan removal of support for older systems. The following information will be sent:"); + } else + { + return MPT_USTRING("") + + MPT_USTRING("When checking for updates, OpenMPT can additionally collect some basic statistical information.") + MPT_USTRING(" ") + + MPT_USTRING("A randomized user ID is created and transmitted alongside the update check. This ID can only be linked to you or your computer by this very ID, which is stored solely on your computer.") + MPT_USTRING(" ") + + MPT_USTRING("OpenMPT will use this information to gather usage statistics and to plan removal of support for older systems.") + MPT_USTRING(" ") + + MPT_USTRING("Without this statistical information, the OpenMPT developers would be blind with respect to what systems are used to run OpenMPT. This makes deciding where to focus development plain guesswork.") + MPT_USTRING("\n") + + MPT_USTRING("OpenMPT would collect the following statistical data points: OpenMPT version, Windows version, type of CPU, amount of RAM, configured update check frequency of OpenMPT.") + ; + } +} -mpt::ustring CUpdateCheck::GetDefaultUpdateURL() + +mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() { return MPT_USTRING("https://update.openmpt.org/check/$VERSION/$GUID"); } +mpt::ustring CUpdateCheck::GetDefaultChannelNextURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/next/$VERSION/$GUID"); +} +mpt::ustring CUpdateCheck::GetDefaultChannelDevelopmentURL() +{ + return MPT_USTRING("https://update.openmpt.org/check/testing/$VERSION/$GUID"); +} + + +mpt::ustring CUpdateCheck::GetDefaultAPIURL() +{ + return MPT_USTRING("https://update.openmpt.org/api/v3/"); +} + + std::atomic<int32> CUpdateCheck::s_InstanceCount(0); @@ -104,16 +139,25 @@ { if(isAutoUpdate) { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(updateCheckPeriod == 0) + if(!TrackerSettings::Instance().UpdateEnabled) { return; } + int updateCheckPeriod = TrackerSettings::Instance().UpdateIntervalDays; + if(updateCheckPeriod < 0) + { + return; + } // Do we actually need to run the update check right now? const time_t now = time(nullptr); - if(difftime(now, TrackerSettings::Instance().UpdateLastUpdateCheck.Get()) < (double)(updateCheckPeriod * 86400)) + const time_t lastCheck = TrackerSettings::Instance().UpdateLastUpdateCheck.Get(); + // Check update interval. Note that we always check for updates when the system time had gone backwards (i.e. when the last update check supposedly happened in the future). + if(difftime(now, lastCheck) > 0.0) { - return; + if(difftime(now, lastCheck) < static_cast<double>(updateCheckPeriod * 86400)) + { + return; + } } // Never ran update checks before, so we notify the user of automatic update checks. @@ -121,7 +165,7 @@ { TrackerSettings::Instance().UpdateShowUpdateHint = false; CString msg; - msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateUpdateCheckPeriod.Get()); + msg.Format(_T("OpenMPT would like to check for updates now, proceed?\n\nNote: In the future, OpenMPT will check for updates every %u days. If you do not want this, you can disable update checks in the setup."), TrackerSettings::Instance().UpdateIntervalDays.Get()); if(Reporting::Confirm(msg, _T("OpenMPT Internet Update")) == cnfNo) { TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(now); @@ -128,6 +172,15 @@ return; } } + } else + { + if(!TrackerSettings::Instance().UpdateEnabled) + { + if(Reporting::Confirm(_T("Update Check is disabled. Do you want to check anyway?"), _T("OpenMPT Internet Update")) != cnfYes) + { + return; + } + } } TrackerSettings::Instance().UpdateShowUpdateHint = false; @@ -137,22 +190,33 @@ return; } - CUpdateCheck::Settings settings; - settings.window = CMainFrame::GetMainFrame(); - settings.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; - settings.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; - settings.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; - settings.autoUpdate = isAutoUpdate; - settings.updateBaseURL = TrackerSettings::Instance().UpdateUpdateURL; - settings.sendStatistics = TrackerSettings::Instance().UpdateSendGUID; - settings.statisticsUUID = TrackerSettings::Instance().VersionInstallGUID; - settings.suggestDifferentBuilds = TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant; - std::thread(CUpdateCheck::ThreadFunc(settings)).detach(); + CUpdateCheck::Context context; + context.window = CMainFrame::GetMainFrame(); + context.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; + context.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; + context.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; + context.autoUpdate = isAutoUpdate; + std::thread(CUpdateCheck::ThreadFunc(CUpdateCheck::Settings(), context)).detach(); } -CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings) +CUpdateCheck::Settings::Settings() + : periodDays(TrackerSettings::Instance().UpdateIntervalDays) + , channel(TrackerSettings::Instance().UpdateChannel) + , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) + , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) + , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) + , apiURL(TrackerSettings::Instance().UpdateAPIURL) + , sendStatistics(TrackerSettings::Instance().UpdateStatistics) + , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) + , suggestDifferentBuilds(TrackerSettings::Instance().UpdateSuggestDifferentBuildVariant) +{ +} + + +CUpdateCheck::ThreadFunc::ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) : settings(settings) + , context(context) { return; } @@ -160,27 +224,103 @@ void CUpdateCheck::ThreadFunc::operator () () { - mpt::SetCurrentThreadPriority(settings.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); - CUpdateCheck::CheckForUpdate(settings); + mpt::SetCurrentThreadPriority(context.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); + CUpdateCheck::CheckForUpdate(settings, context); } -// Run update check (independent thread) -CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +std::string CUpdateCheck::GetStatisticsDataV3(const Settings &settings) { - - HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + JSON::value j; + j["OpenMPT"]["Version"] = mpt::ufmt::val(Version::Current()); + j["OpenMPT"]["BuildVariant"] = BuildVariants().GuessCurrentBuildName(); + j["OpenMPT"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetProcessArchitecture()); + j["Update"]["PeriodDays"] = settings.periodDays; + j["System"]["Windows"]["Version"]["Name"] = mpt::Windows::Version::Current().GetName(); + j["System"]["Windows"]["Version"]["Major"] = mpt::Windows::Version::Current().GetSystem().Major; + j["System"]["Windows"]["Version"]["Minor"] = mpt::Windows::Version::Current().GetSystem().Minor; + j["System"]["Windows"]["ServicePack"]["Major"] = mpt::Windows::Version::Current().GetServicePack().Major; + j["System"]["Windows"]["ServicePack"]["Minor"] = mpt::Windows::Version::Current().GetServicePack().Minor; + j["System"]["Windows"]["Build"] = mpt::Windows::Version::Current().GetBuild(); + j["System"]["Windows"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetHostArchitecture()); + j["System"]["Windows"]["IsWine"] = mpt::Windows::IsWine(); + std::vector<mpt::Windows::Architecture> architectures = mpt::Windows::GetSupportedProcessArchitectures(mpt::Windows::GetHostArchitecture()); + for(const auto & arch : architectures) + { + j["System"]["Windows"]["ProcessArchitectures"][mpt::ToCharset(mpt::CharsetUTF8, mpt::Windows::Name(arch))] = true; + } + j["System"]["Memory"] = mpt::Windows::GetSystemMemorySize() / 1024 / 1024; // MB + if(mpt::Windows::IsWine()) + { + mpt::Wine::VersionContext v; + j["System"]["Windows"]["Wine"]["Version"]["Raw"] = v.RawVersion(); + if(v.Version().IsValid()) + { + j["System"]["Windows"]["Wine"]["Version"]["Major"] = v.Version().GetMajor(); + j["System"]["Windows"]["Wine"]["Version"]["Minor"] = v.Version().GetMinor(); + j["System"]["Windows"]["Wine"]["Version"]["Update"] = v.Version().GetUpdate(); + } + j["System"]["Windows"]["Wine"]["HostSysName"] = v.RawHostSysName(); + } + #ifdef ENABLE_ASM + j["System"]["Processor"]["Vendor"] = std::string(mpt::String::ReadAutoBuf(ProcVendorID)); + j["System"]["Processor"]["Brand"] = std::string(mpt::String::ReadAutoBuf(ProcBrandID)); + j["System"]["Processor"]["Id"]["Family"] = ProcFamily; + j["System"]["Processor"]["Id"]["Model"] = ProcModel; + j["System"]["Processor"]["Id"]["Stepping"] = ProcStepping; + j["System"]["Processor"]["Features"]["lm"] = ((GetRealProcSupport() & PROCSUPPORT_LM) ? true : false); + j["System"]["Processor"]["Features"]["cmov"] = ((GetRealProcSupport() & PROCSUPPORT_CMOV) ? true : false); + j["System"]["Processor"]["Features"]["mmx"] = ((GetRealProcSupport() & PROCSUPPORT_MMX) ? true : false); + j["System"]["Processor"]["Features"]["mmxext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_MMXEXT) ? true : false); + j["System"]["Processor"]["Features"]["3dnow"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOW) ? true : false); + j["System"]["Processor"]["Features"]["3dnowext"] = ((GetRealProcSupport() & PROCSUPPORT_AMD_3DNOWEXT) ? true : false); + j["System"]["Processor"]["Features"]["sse"] = ((GetRealProcSupport() & PROCSUPPORT_SSE) ? true : false); + j["System"]["Processor"]["Features"]["sse2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE2) ? true : false); + j["System"]["Processor"]["Features"]["sse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSE3) ? true : false); + j["System"]["Processor"]["Features"]["ssse3"] = ((GetRealProcSupport() & PROCSUPPORT_SSSE3) ? true : false); + j["System"]["Processor"]["Features"]["sse4_1"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_1) ? true : false); + j["System"]["Processor"]["Features"]["sse4_2"] = ((GetRealProcSupport() & PROCSUPPORT_SSE4_2) ? true : false); + #endif + return j.dump(1, '\t'); +} - mpt::ustring updateURL = settings.updateBaseURL; - if(updateURL.empty()) + +mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) +{ + mpt::ustring updateURL; + if(settings.channel == UpdateChannelRelease) { - updateURL = GetDefaultUpdateURL(); + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } + } else if(settings.channel == UpdateChannelNext) + { + updateURL = settings.channelNextURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelNextURL(); + } + } else if(settings.channel == UpdateChannelDevelopment) + { + updateURL = settings.channelDevelopmentURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelDevelopmentURL(); + } + } else + { + updateURL = settings.channelReleaseURL; + if(updateURL.empty()) + { + updateURL = GetDefaultChannelReleaseURL(); + } } if(updateURL.find(MPT_USTRING("://")) == mpt::ustring::npos) { updateURL = MPT_USTRING("https://") + updateURL; } - // Build update URL updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$VERSION"), mpt::uformat(MPT_USTRING("%1-%2-%3")) ( Version::Current() @@ -188,15 +328,44 @@ , settings.sendStatistics ? mpt::Windows::Version::Current().GetNameShort() : MPT_USTRING("unknown") )); updateURL = mpt::String::Replace(updateURL, MPT_USTRING("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : MPT_USTRING("anonymous")); + return updateURL; +} + +// Run update check (independent thread) +CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings) +{ + + HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + // Establish a connection. HTTP::Request request; - request.SetURI(ParseURI(updateURL)); + request.SetURI(ParseURI(GetUpdateURLV2(settings))); request.method = HTTP::Method::Get; request.flags = HTTP::NoCache; HTTP::Result resultHTTP = internet(request.InsecureTLSDowngradeWindowsXP()); + if(settings.sendStatistics) + { + HTTP::Request requestStatistics; + if(settings.statisticsUUID.IsValid()) + { + requestStatistics.SetURI(ParseURI(settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID))); + requestStatistics.method = HTTP::Method::Put; + } else + { + requestStatistics.SetURI(ParseURI(settings.apiURL + MPT_USTRING("statistics/"))); + requestStatistics.method = HTTP::Method::Post; + } + requestStatistics.dataMimeType = HTTP::MimeType::JSON(); + requestStatistics.acceptMimeTypes = HTTP::MimeTypes::JSON(); + std::string jsondata = GetStatisticsDataV3(settings); + MPT_LOG(LogInformation, "Update", mpt::ToUnicode(mpt::CharsetUTF8, jsondata)); + requestStatistics.data = mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(jsondata)); + internet(requestStatistics.InsecureTLSDowngradeWindowsXP()); + } + // Retrieve HTTP status code. if(resultHTTP.Status >= 400) { @@ -244,12 +413,12 @@ } -void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings) +void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) { // �ncremented before starting the thread MPT_ASSERT(s_InstanceCount.load() >= 1); CUpdateCheck::Result result; - settings.window->SendMessage(settings.msgProgress, settings.autoUpdate ? 1 : 0, s_InstanceCount.load()); + context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, s_InstanceCount.load()); try { try @@ -264,12 +433,12 @@ } } catch(const CUpdateCheck::Error &e) { - settings.window->SendMessage(settings.msgFailure, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); + context.window->SendMessage(context.msgFailure, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); return; } - settings.window->SendMessage(settings.msgSuccess, settings.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); + context.window->SendMessage(context.msgSuccess, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&result)); s_InstanceCount.fetch_sub(1); MPT_ASSERT(s_InstanceCount.load() >= 0); } @@ -347,14 +516,13 @@ // CUpdateSetupDlg BEGIN_MESSAGE_MAP(CUpdateSetupDlg, CPropertyPage) - ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) - ON_COMMAND(IDC_BUTTON2, &CUpdateSetupDlg::OnResetURL) - ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_RADIO4, &CUpdateSetupDlg::OnSettingsChanged) - ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) - ON_EN_CHANGE(IDC_EDIT1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK_UPDATEENABLED, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO1, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO2, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) + ON_CBN_SELCHANGE(IDC_COMBO_UPDATEFREQUENCY, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) END_MESSAGE_MAP() @@ -366,29 +534,82 @@ } +void CUpdateSetupDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO_UPDATEFREQUENCY, m_CbnUpdateFrequency); +} + + BOOL CUpdateSetupDlg::OnInitDialog() { CPropertyPage::OnInitDialog(); + CheckDlgButton(IDC_CHECK_UPDATEENABLED, TrackerSettings::Instance().UpdateEnabled ? BST_CHECKED : BST_UNCHECKED); + int radioID = 0; - int periodDays = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(periodDays >= 30) + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(updateChannel == UpdateChannelRelease) { - radioID = IDC_RADIO4; - } else if(periodDays >= 7) + radioID = IDC_RADIO1; + } else if(updateChannel == UpdateChannelNext) { + radioID = IDC_RADIO2; + } else if(updateChannel == UpdateChannelDevelopment) + { radioID = IDC_RADIO3; - } else if(periodDays >= 1) - { - radioID = IDC_RADIO2; } else { radioID = IDC_RADIO1; } - CheckRadioButton(IDC_RADIO1, IDC_RADIO4, radioID); - CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateSendGUID ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(IDC_EDIT1, mpt::ToCString(TrackerSettings::Instance().UpdateUpdateURL.Get())); + CheckRadioButton(IDC_RADIO1, IDC_RADIO3, radioID); + int32 periodDays = TrackerSettings::Instance().UpdateIntervalDays; + int ndx; + + ndx = m_CbnUpdateFrequency.AddString(_T("always")); + m_CbnUpdateFrequency.SetItemData(ndx, 0); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("daily")); + m_CbnUpdateFrequency.SetItemData(ndx, 1); + if(periodDays >= 30) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("weekly")); + m_CbnUpdateFrequency.SetItemData(ndx, 7); + if(periodDays >= 7) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("monthly")); + m_CbnUpdateFrequency.SetItemData(ndx, 30); + if(periodDays >= 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + ndx = m_CbnUpdateFrequency.AddString(_T("never")); + m_CbnUpdateFrequency.SetItemData(ndx, ~(DWORD_PTR)0); + if(periodDays < 0) + { + m_CbnUpdateFrequency.SetCurSel(ndx); + } + + CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateStatistics ? BST_CHECKED : BST_UNCHECKED); + + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->SetWindowText(mpt::ToCString(CUpdateCheck::GetStatisticsUserInformation(true))); + + UpdateStatistics(); + + EnableDisableDialog(); + m_SettingChangedNotifyGuard.Register(this); SettingChanged(TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()); @@ -396,6 +617,43 @@ } +void CUpdateSetupDlg::UpdateStatistics() +{ + CUpdateCheck::Settings settings; + + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + + CString updateURL; + GetDlgItemText(IDC_EDIT1, updateURL); + + settings.periodDays = updateCheckPeriod; + settings.channel = updateChannel; + settings.sendStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); + + mpt::ustring statistics; + statistics += MPT_USTRING("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + MPT_ULITERAL("\n"); + statistics += MPT_ULITERAL("\n"); + if(settings.sendStatistics) + { + if(settings.statisticsUUID.IsValid()) + { + statistics += MPT_USTRING("PUT ") + settings.apiURL + mpt::format(MPT_USTRING("statistics/%1"))(settings.statisticsUUID) + MPT_ULITERAL("\n"); + } else + { + statistics += MPT_USTRING("POST ") + settings.apiURL + MPT_USTRING("statistics/") + MPT_ULITERAL("\n"); + } + statistics += mpt::String::Replace(mpt::ToUnicode(mpt::CharsetUTF8, CUpdateCheck::GetStatisticsDataV3(settings)), MPT_USTRING("\t"), MPT_USTRING(" ")); + statistics += MPT_ULITERAL("\n"); + } + SetDlgItemText(IDC_EDIT_STATISTICS, mpt::ToCString(mpt::String::Replace(statistics, MPT_USTRING("\n"), MPT_USTRING("\r\n")))); +} + + void CUpdateSetupDlg::SettingChanged(const SettingPath &changedPath) { if(changedPath == TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()) @@ -420,20 +678,61 @@ } +void CUpdateSetupDlg::EnableDisableDialog() +{ + + BOOL status = ((IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED) ? TRUE : FALSE); + + GetDlgItem(IDC_STATIC_UDATECHANNEL)->EnableWindow(status); + GetDlgItem(IDC_RADIO1)->EnableWindow(status); + GetDlgItem(IDC_RADIO2)->EnableWindow(status); + GetDlgItem(IDC_RADIO3)->EnableWindow(status); + + GetDlgItem(IDC_STATIC_UPDATECHECK)->EnableWindow(status); + GetDlgItem(IDC_STATIC_UPDATEFREQUENCY)->EnableWindow(status); + GetDlgItem(IDC_COMBO_UPDATEFREQUENCY)->EnableWindow(status); + GetDlgItem(IDC_BUTTON1)->EnableWindow(status); + GetDlgItem(IDC_LASTUPDATE)->EnableWindow(status); + + GetDlgItem(IDC_STATIC_UPDATEPRIVACY)->EnableWindow(status); + GetDlgItem(IDC_CHECK1)->EnableWindow(status); + GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->EnableWindow(status); + GetDlgItem(IDC_EDIT_STATISTICS)->EnableWindow(status); + + // disabled features + GetDlgItem(IDC_CHECK_UPDATEENABLED)->EnableWindow(FALSE); + GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); + +} + + +void CUpdateSetupDlg::OnSettingsChanged() +{ + EnableDisableDialog(); + UpdateStatistics(); + SetModified(TRUE); +} + + void CUpdateSetupDlg::OnOK() { - int updateCheckPeriod = TrackerSettings::Instance().UpdateUpdateCheckPeriod; - if(IsDlgButtonChecked(IDC_RADIO1)) updateCheckPeriod = 0; - if(IsDlgButtonChecked(IDC_RADIO2)) updateCheckPeriod = 1; - if(IsDlgButtonChecked(IDC_RADIO3)) updateCheckPeriod = 7; - if(IsDlgButtonChecked(IDC_RADIO4)) updateCheckPeriod = 31; + int updateChannel = TrackerSettings::Instance().UpdateChannel; + if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; + if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; + if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; + int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); + CString updateURL; GetDlgItemText(IDC_EDIT1, updateURL); - TrackerSettings::Instance().UpdateUpdateCheckPeriod = updateCheckPeriod; - TrackerSettings::Instance().UpdateUpdateURL = mpt::ToUnicode(updateURL); - TrackerSettings::Instance().UpdateSendGUID = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); + if(GetDlgItem(IDC_CHECK_UPDATEENABLED)->IsWindowEnabled() != FALSE) + { + TrackerSettings::Instance().UpdateEnabled = (IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED); + } + TrackerSettings::Instance().UpdateIntervalDays = updateCheckPeriod; + TrackerSettings::Instance().UpdateChannel = updateChannel; + TrackerSettings::Instance().UpdateStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); CPropertyPage::OnOK(); } @@ -452,10 +751,4 @@ } -void CUpdateSetupDlg::OnResetURL() -{ - SetDlgItemText(IDC_EDIT1, mpt::ToCString(CUpdateCheck::GetDefaultUpdateURL())); -} - - OPENMPT_NAMESPACE_END Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 10965) +++ mptrack/UpdateCheck.h (working copy) @@ -24,6 +24,13 @@ OPENMPT_NAMESPACE_BEGIN +enum UpdateChannel +{ + UpdateChannelRelease = 1, + UpdateChannelNext = 2, + UpdateChannelDevelopment = 3, +}; + class CUpdateCheck { @@ -33,7 +40,13 @@ public: - static mpt::ustring GetDefaultUpdateURL(); + static mpt::ustring GetStatisticsUserInformation(bool shortText); + + static mpt::ustring GetDefaultChannelReleaseURL(); + static mpt::ustring GetDefaultChannelNextURL(); + static mpt::ustring GetDefaultChannelDevelopmentURL(); + + static mpt::ustring GetDefaultAPIURL(); int32 GetNumCurrentRunningInstances(); @@ -42,7 +55,7 @@ public: - struct Settings + struct Context { CWnd *window; UINT msgProgress; @@ -49,10 +62,20 @@ UINT msgSuccess; UINT msgFailure; bool autoUpdate; - mpt::ustring updateBaseURL; // URL where the version check should be made. + }; + + struct Settings + { + int32 periodDays; + uint32 channel; + mpt::ustring channelReleaseURL; + mpt::ustring channelNextURL; + mpt::ustring channelDevelopmentURL; + mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; bool suggestDifferentBuilds; + Settings(); }; class Error @@ -86,6 +109,14 @@ static void ShowSuccessGUI(WPARAM wparam, LPARAM lparam); static void ShowFailureGUI(WPARAM wparam, LPARAM lparam); +public: + + // v2 + static mpt::ustring GetUpdateURLV2(const Settings &settings); + + // v3 + static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 + protected: static void StartUpdateCheckAsync(bool autoUpdate); @@ -93,11 +124,12 @@ struct ThreadFunc { CUpdateCheck::Settings settings; - ThreadFunc(const CUpdateCheck::Settings &settings); + CUpdateCheck::Context context; + ThreadFunc(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); void operator () (); }; - static void CheckForUpdate(const CUpdateCheck::Settings &settings); + static void CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); static CUpdateCheck::Result SearchUpdate(const CUpdateCheck::Settings &settings); // may throw @@ -111,6 +143,7 @@ CUpdateSetupDlg(); protected: + void DoDataExchange(CDataExchange *pDX) override; BOOL OnInitDialog() override; void OnOK() override; BOOL OnSetActive() override; @@ -117,13 +150,15 @@ void SettingChanged(const SettingPath &changedPath) override; - afx_msg void OnSettingsChanged() { SetModified(TRUE); } + afx_msg void OnSettingsChanged(); afx_msg void OnCheckNow(); - afx_msg void OnResetURL(); + void EnableDisableDialog(); + void UpdateStatistics(); DECLARE_MESSAGE_MAP() private: SettingChangedNotifyGuard m_SettingChangedNotifyGuard; + CComboBox m_CbnUpdateFrequency; }; Index: mptrack/WelcomeDialog.cpp =================================================================== --- mptrack/WelcomeDialog.cpp (revision 10965) +++ mptrack/WelcomeDialog.cpp (working copy) @@ -119,6 +119,8 @@ combo->SetItemDataPtr(combo->AddString(_T("FastTracker 2")), (void*)("US_mpt-ft2_classic")); CheckDlgButton(IDC_CHECK1, BST_CHECKED); + CheckDlgButton(IDC_CHECK3, BST_UNCHECKED); + GetDlgItem(IDC_STATIC_WELCOME_STATISTICS)->SetWindowText(mpt::ToCString(mpt::String::Replace(CUpdateCheck::GetStatisticsUserInformation(false), MPT_USTRING("\n"), MPT_USTRING(" ")))); CheckDlgButton(IDC_CHECK2, (TrackerSettings::Instance().patternFont.Get().name == PATTERNFONT_LARGE) ? BST_CHECKED : BST_UNCHECKED); ShowWindow(SW_SHOW); @@ -147,7 +149,8 @@ CDialog::OnOK(); bool runUpdates = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED; - TrackerSettings::Instance().UpdateUpdateCheckPeriod = (runUpdates ? 7 : 0); + TrackerSettings::Instance().UpdateIntervalDays = (runUpdates ? 7 : 0); + TrackerSettings::Instance().UpdateStatistics = (IsDlgButtonChecked(IDC_CHECK3) != BST_UNCHECKED); if(IsDlgButtonChecked(IDC_CHECK2) != BST_UNCHECKED) { FontSetting font = TrackerSettings::Instance().patternFont; | ||||
Has the bug occurred in previous versions? | |||||
Tested code revision (in case you know it) | |||||
related to | 0000649 | resolved | manx | modern file type registration (was: |
related to | 0001428 | resolved | Saga Musix | Avoid modal update notifcation dialog |
related to | 0001466 | resolved | manx | OpenMPT fails to re-open previously opened files when restarted via RestartManager |
related to | 0001532 | resolved | manx | Remove legacy update code |
related to | 0001123 | resolved | manx | Provide unified multi-arch installer |
related to | 0001185 | resolved | manx | Restructure MSVC bin directory layout |
related to | 0001186 | resolved | manx | Remove Windows XP support |
related to | 0001213 | resolved | manx | Admin-level installer modifies per-user directories |
related to | 0001214 | resolved | manx | Remove portable mode from installer |
related to | 0001377 | resolved | Saga Musix | Making OpenMPT signed software |
I'd prefer to use a new update URL. That way, the client can also send JSON data, which could easily be extended without breaking backwards compatibility in the future (which is a major hassle with the current way of doing things). Other than that, I really like the proposal to send all build variants. That's exactly what I also had in mind. Additionally, we should at least take a look at WinSparkle ( https://winsparkle.org/ ). I do not know if the sparkle specification would be enough for what OpenMPT needs, but even if it is not, and even if we do not use RSS/XML (like Sparkle), there might be good ideas in there to copy or mimic. |
|
Even though downloading the automated updater from a TLS host with a valid certificate is technically and in practice enough to ensure authenticity, we might want to also look into additionally signing the installer itself. Either with a proper code signing certificate, or with a custom pinned key. |
|
I have looked into code signing certificates several times in the past, and there used to be free certificates for open-source developers from Certum, but those are no longer free. While they are relatively cheap, they still require documents for verification that I would be hesistant to provide (see https://www.certum.eu/certum/cert,offer_en_open_source_cs.xml) |
|
Which is why I suggested as an alternative just additionally signing the updater with custom key even without an official certificate which would still guard against any attacks on the domain. In particular, especially for signing the updater there is actually no semantic requirement to rely on any common certificate authority infrastructure. |
|
Attached a quick mockup of a suggested update settings dialog. Changes:
All but the last change can already be implemented without actually changing the update/installer mechanism itself. |
|
|
|
Patch committed as r10970. |
|
Since r12991 / 1.30.00.04, the new multi-arch installer supports silent auto-updates via |
|
autoupdate-v10.patch (75,630 bytes)
Index: common/BuildSettings.h =================================================================== --- common/BuildSettings.h (revision 13367) +++ common/BuildSettings.h (working copy) @@ -194,6 +194,8 @@ #if defined(MODPLUG_TRACKER) +#define MPT_UPDATE_LEGACY 1 + // Enable built-in test suite. #if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) #define ENABLE_TESTS Index: common/versionNumber.h =================================================================== --- common/versionNumber.h (revision 13367) +++ common/versionNumber.h (working copy) @@ -18,6 +18,6 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 30 #define VER_MINOR 00 -#define VER_MINORMINOR 07 +#define VER_MINORMINOR 08 OPENMPT_NAMESPACE_END Index: installer/generate_update_json.py =================================================================== --- installer/generate_update_json.py (revision 13367) +++ installer/generate_update_json.py (working copy) @@ -161,7 +161,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-Setup.update.json", "type": "installer", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":6, "version_minor":1, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": { "x86":True }, @@ -172,7 +172,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-portable-x86.update.json", "type": "archive", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":10, "version_minor":0, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": {}, @@ -183,7 +183,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-portable-x86-legacy.update.json", "type": "archive", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":6, "version_minor":1, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": {}, @@ -194,7 +194,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-portable-amd64.update.json", "type": "archive", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":10, "version_minor":0, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": {}, @@ -205,7 +205,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-portable-amd64-legacy.update.json", "type": "archive", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":6, "version_minor":1, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": {}, @@ -216,7 +216,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-portable-arm.update.json", "type": "archive", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":10, "version_minor":0, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": {}, @@ -227,7 +227,7 @@ "url": "https://builds.openmpt.org/builds/auto/openmpt/pkg.win/" + OPENMPT_VERSION_MAJORMAJOR + "." + OPENMPT_VERSION_MAJOR + "/OpenMPT-" + version + "-portable-arm64.update.json", "type": "archive", "can_autoupdate": True, - "autoupdate_minversion": "1.30.00.04", + "autoupdate_minversion": "1.30.00.08", "os": "windows", "required_windows_version": { "version_major":10, "version_minor":0, "servicepack_major":0, "servicepack_minor":0, "build":0, "wine_major":1, "wine_minor":8, "wine_update":0 }, "required_architectures": {}, Index: mptrack/MainFrm.cpp =================================================================== --- mptrack/MainFrm.cpp (revision 13367) +++ mptrack/MainFrm.cpp (working copy) @@ -46,6 +46,7 @@ #include "../soundlib/plugins/PluginManager.h" #include "Vstplug.h" #include "FileDialog.h" +#include "ProgressDialog.h" #include <HtmlHelp.h> @@ -109,9 +110,11 @@ ON_MESSAGE(WM_MOD_SETMODIFIED, &CMainFrame::OnSetModified) ON_COMMAND(ID_INTERNETUPDATE, &CMainFrame::OnInternetUpdate) ON_COMMAND(ID_HELP_SHOWSETTINGSFOLDER, &CMainFrame::OnShowSettingsFolder) + ON_MESSAGE(MPT_WM_APP_UPDATECHECK_START, &CMainFrame::OnUpdateCheckStart) ON_MESSAGE(MPT_WM_APP_UPDATECHECK_PROGRESS, &CMainFrame::OnUpdateCheckProgress) + ON_MESSAGE(MPT_WM_APP_UPDATECHECK_CANCELED, &CMainFrame::OnUpdateCheckCanceled) + ON_MESSAGE(MPT_WM_APP_UPDATECHECK_FAILURE, &CMainFrame::OnUpdateCheckFailure) ON_MESSAGE(MPT_WM_APP_UPDATECHECK_SUCCESS, &CMainFrame::OnUpdateCheckSuccess) - ON_MESSAGE(MPT_WM_APP_UPDATECHECK_FAILURE, &CMainFrame::OnUpdateCheckFailure) ON_COMMAND(ID_HELPSHOW, &CMainFrame::OnHelp) ON_COMMAND_RANGE(ID_MRU_LIST_FIRST, ID_MRU_LIST_LAST, &CMainFrame::OnOpenMRUItem) @@ -1904,8 +1907,10 @@ if(mpt::Windows::IsWine()) dlg.AddPage(&winedlg); m_bOptionsLocked = true; m_SoundCardOptionsDialog = &sounddlg; + m_UpdateOptionsDialog = &updatedlg; dlg.DoModal(); m_SoundCardOptionsDialog = nullptr; + m_UpdateOptionsDialog = nullptr; m_bOptionsLocked = false; m_wndTree.OnOptionsChanged(); } @@ -2552,18 +2557,110 @@ } + +class CUpdateCheckProgressDialog + : public CProgressDialog +{ +public: + CUpdateCheckProgressDialog(CWnd *parent) + : CProgressDialog(parent) + { + return; + } + void Run() override + { + } +}; + +static std::unique_ptr<CUpdateCheckProgressDialog> g_UpdateCheckProgressDialog = nullptr; + + + +LRESULT CMainFrame::OnUpdateCheckStart(WPARAM wparam, LPARAM lparam) +{ + bool isAutoUpdate = CUpdateCheck::IsAutoUpdateFromMessage(wparam, lparam); + CString updateText = _T("Checking for updates..."); + if(isAutoUpdate) + { + SetHelpText(updateText); + } else if(m_UpdateOptionsDialog) + { + m_UpdateOptionsDialog->SetDlgItemText(IDC_LASTUPDATE, updateText); + } else + { + if(!g_UpdateCheckProgressDialog) + { + g_UpdateCheckProgressDialog = std::make_unique<CUpdateCheckProgressDialog>(CMainFrame::GetMainFrame()); + g_UpdateCheckProgressDialog->Create(IDD_PROGRESS, CMainFrame::GetMainFrame()); + g_UpdateCheckProgressDialog->SetTitle(_T("Checking for updates...")); + g_UpdateCheckProgressDialog->SetText(_T("Checking for updates...")); + g_UpdateCheckProgressDialog->SetAbortText(_T("&Cancel")); + g_UpdateCheckProgressDialog->SetRange(0, 100); + g_UpdateCheckProgressDialog->ShowWindow(SW_SHOWDEFAULT); + } + if(g_UpdateCheckProgressDialog) + { + g_UpdateCheckProgressDialog->SetProgress(0); + } + } + return TRUE; +} + + LRESULT CMainFrame::OnUpdateCheckProgress(WPARAM wparam, LPARAM lparam) { - MPT_UNREFERENCED_PARAMETER(wparam); - MPT_UNREFERENCED_PARAMETER(lparam); + bool isAutoUpdate = wparam ? true : false; + CString updateText = MPT_CFORMAT("Checking for updates... {}%")(lparam); + if(isAutoUpdate) + { + SetHelpText(updateText); + } else if(m_UpdateOptionsDialog) + { + m_UpdateOptionsDialog->SetDlgItemText(IDC_LASTUPDATE, updateText); + } else + { + if(g_UpdateCheckProgressDialog) + { + g_UpdateCheckProgressDialog->SetProgress(lparam); + if(g_UpdateCheckProgressDialog->m_abort) + { + return FALSE; + } + } + } return TRUE; } -LRESULT CMainFrame::OnUpdateCheckSuccess(WPARAM wparam, LPARAM lparam) +LRESULT CMainFrame::OnUpdateCheckCanceled(WPARAM wparam, LPARAM lparam) { - TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(CUpdateCheck::ResultFromMessage(wparam, lparam).CheckTime); - CUpdateCheck::ShowSuccessGUI(wparam, lparam); + bool isAutoUpdate = CUpdateCheck::IsAutoUpdateFromMessage(wparam, lparam); + CString updateText = _T("Checking for updates... Canceled."); + if(isAutoUpdate) + { + SetHelpText(updateText); + } else if(m_UpdateOptionsDialog) + { + m_UpdateOptionsDialog->SetDlgItemText(IDC_LASTUPDATE, updateText); + m_UpdateOptionsDialog->SettingChanged(TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()); + } else + { + if(g_UpdateCheckProgressDialog) + { + g_UpdateCheckProgressDialog->DestroyWindow(); + g_UpdateCheckProgressDialog = nullptr; + } + } + if(isAutoUpdate) + { + SetHelpText(_T("")); + } else if(m_UpdateOptionsDialog) + { + // nothing + } else + { + // nothing + } return TRUE; } @@ -2570,11 +2667,81 @@ LRESULT CMainFrame::OnUpdateCheckFailure(WPARAM wparam, LPARAM lparam) { + bool isAutoUpdate = CUpdateCheck::IsAutoUpdateFromMessage(wparam, lparam); + CString updateText = MPT_CFORMAT("Checking for updates failed: {}")(CUpdateCheck::GetFailureMessage(wparam, lparam)).GetString(); + if(isAutoUpdate) + { + SetHelpText(updateText); + } else if(m_UpdateOptionsDialog) + { + m_UpdateOptionsDialog->SetDlgItemText(IDC_LASTUPDATE, updateText); + m_UpdateOptionsDialog->SettingChanged(TrackerSettings::Instance().UpdateLastUpdateCheck.GetPath()); + } else + { + if(g_UpdateCheckProgressDialog) + { + g_UpdateCheckProgressDialog->DestroyWindow(); + g_UpdateCheckProgressDialog = nullptr; + } + } CUpdateCheck::ShowFailureGUI(wparam, lparam); + if(isAutoUpdate) + { + SetHelpText(_T("")); + } else if(m_UpdateOptionsDialog) + { + // nothing + } else + { + // nothing + } return TRUE; } +LRESULT CMainFrame::OnUpdateCheckSuccess(WPARAM wparam, LPARAM lparam) +{ + bool isAutoUpdate = CUpdateCheck::IsAutoUpdateFromMessage(wparam, lparam); + CString updateText = MPT_CFORMAT("Checking for updates... Done.")().GetString(); + // TODO: + // UpdateToolbarUpdateIndicator(CUpdateCheck::ResultFromMessage(wparam, lparam)); + if(isAutoUpdate) + { + SetHelpText(updateText); + } else if(m_UpdateOptionsDialog) + { + m_UpdateOptionsDialog->SetDlgItemText(IDC_LASTUPDATE, updateText); + } else + { + SetHelpText(updateText); + if(g_UpdateCheckProgressDialog) + { + g_UpdateCheckProgressDialog->DestroyWindow(); + g_UpdateCheckProgressDialog = nullptr; + } + } + CUpdateCheck::ShowSuccessGUI(wparam, lparam); + if(isAutoUpdate) + { + SetHelpText(_T("")); + } else if(m_UpdateOptionsDialog) + { + // nothing + } else + { + // nothing + } + return TRUE; +} + + +void CMainFrame::OnToolbarUpdateIndicatorClick() +{ + // TODO + CUpdateCheck::DoManualUpdateCheck(); +} + + void CMainFrame::OnHelp() { CView *view = GetActiveView(); Index: mptrack/Mainfrm.h =================================================================== --- mptrack/Mainfrm.h (revision 13367) +++ mptrack/Mainfrm.h (working copy) @@ -60,9 +60,11 @@ enum { - MPT_WM_APP_UPDATECHECK_PROGRESS = WM_APP + 1, - MPT_WM_APP_UPDATECHECK_SUCCESS = WM_APP + 2, - MPT_WM_APP_UPDATECHECK_FAILURE = WM_APP + 3, + MPT_WM_APP_UPDATECHECK_START = WM_APP + 1, + MPT_WM_APP_UPDATECHECK_PROGRESS = WM_APP + 2, + MPT_WM_APP_UPDATECHECK_CANCELED = WM_APP + 3, + MPT_WM_APP_UPDATECHECK_FAILURE = WM_APP + 4, + MPT_WM_APP_UPDATECHECK_SUCCESS = WM_APP + 5, }; enum @@ -303,6 +305,7 @@ UINT m_nAvgMixChn = 0, m_nMixChn = 0; // Misc class COptionsSoundcard *m_SoundCardOptionsDialog = nullptr; + class CUpdateSetupDlg *m_UpdateOptionsDialog = nullptr; DWORD helpCookie = 0; bool m_bOptionsLocked = false; @@ -529,9 +532,12 @@ afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM); afx_msg void OnInternetUpdate(); afx_msg void OnShowSettingsFolder(); + afx_msg LRESULT OnUpdateCheckStart(WPARAM wparam, LPARAM lparam); afx_msg LRESULT OnUpdateCheckProgress(WPARAM wparam, LPARAM lparam); + afx_msg LRESULT OnUpdateCheckCanceled(WPARAM wparam, LPARAM lparam); + afx_msg LRESULT OnUpdateCheckFailure(WPARAM wparam, LPARAM lparam); afx_msg LRESULT OnUpdateCheckSuccess(WPARAM wparam, LPARAM lparam); - afx_msg LRESULT OnUpdateCheckFailure(WPARAM wparam, LPARAM lparam); + afx_msg void OnToolbarUpdateIndicatorClick(); afx_msg void OnHelp(); afx_msg void OnDropFiles(HDROP hDropInfo); afx_msg BOOL OnQueryEndSession(); Index: mptrack/Mptrack.cpp =================================================================== --- mptrack/Mptrack.cpp (revision 13367) +++ mptrack/Mptrack.cpp (working copy) @@ -1069,9 +1069,6 @@ new WelcomeDlg(m_pMainWnd); } else { - - CUpdateCheck::DoAutoUpdateCheck(); - bool deprecatedSoundDevice = GetSoundDevicesManager()->FindDeviceInfo(TrackerSettings::Instance().GetSoundDeviceIdentifier()).IsDeprecated(); bool showSettings = deprecatedSoundDevice && !TrackerSettings::Instance().m_SoundDeprecatedDeviceWarningShown && (Reporting::Confirm( U_("You have currently selected a sound device which is deprecated. MME/WaveOut and DirectSound support will be removed in a future OpenMPT version.\n") + @@ -1098,6 +1095,14 @@ pMainFrame->PlayPreview(); } + if(!TrackerSettings::Instance().FirstRun) + { + if(CUpdateCheck::IsSuitableUpdateMoment()) + { + CUpdateCheck::DoAutoUpdateCheck(); + } + } + return TRUE; } Index: mptrack/mptrack.rc =================================================================== --- mptrack/mptrack.rc (revision 13367) +++ mptrack/mptrack.rc (working copy) @@ -246,24 +246,26 @@ BEGIN CONTROL "Enable Online &Update Check",IDC_CHECK_UPDATEENABLED, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,6,106,10 - GROUPBOX "Check for Updates",IDC_STATIC_UPDATECHECK,6,24,276,48 - LTEXT "Automatically check on program &start:",IDC_STATIC_UPDATEFREQUENCY,12,36,126,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_UPDATEFREQUENCY,138,36,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Check now...",IDC_BUTTON1,216,36,60,12 - LTEXT "",IDC_LASTUPDATE,12,55,264,12 - GROUPBOX "Privacy Settings",IDC_STATIC_UPDATEPRIVACY,6,78,276,84 + GROUPBOX "Check for Updates",IDC_STATIC_UPDATECHECK,6,24,276,66 + CONTROL "&Install Updates automatically",IDC_CHECK_UPDATEINSTALLAUTOMATICALLY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,264,12 + LTEXT "Automatically check on program &start:",IDC_STATIC_UPDATEFREQUENCY,12,54,126,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_UPDATEFREQUENCY,138,54,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Check now...",IDC_BUTTON1,216,54,60,12 + LTEXT "",IDC_LASTUPDATE,12,73,264,12 + GROUPBOX "Privacy Settings",IDC_STATIC_UPDATEPRIVACY,6,96,276,84 CONTROL "&Allow OpenMPT to collect basic statistics about your system configuration",IDC_CHECK1, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,90,264,12 - LTEXT "",IDC_STATIC_UPDATEPRIVACYTEXT,12,102,264,36 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,108,264,12 + LTEXT "",IDC_STATIC_UPDATEPRIVACYTEXT,12,120,264,36 CONTROL "<a>Show which information would be transmitted to OpenMPT...</a>",IDC_SYSLINK1, - "SysLink",WS_TABSTOP,12,144,264,12 - GROUPBOX "Update Channel",IDC_STATIC_UDATECHANNEL,6,174,276,52 + "SysLink",WS_TABSTOP,12,162,264,12 + GROUPBOX "Update Channel",IDC_STATIC_UDATECHANNEL,6,192,276,52 CONTROL "&Release: Official stable released versions only (recommended)",IDC_RADIO1, - "Button",BS_AUTORADIOBUTTON,12,186,264,10 + "Button",BS_AUTORADIOBUTTON,12,204,264,10 CONTROL "&Next: Previews of the next official stable release",IDC_RADIO2, - "Button",BS_AUTORADIOBUTTON,12,199,264,10 + "Button",BS_AUTORADIOBUTTON,12,217,264,10 CONTROL "&Development: Bleeding-edge development versions",IDC_RADIO3, - "Button",BS_AUTORADIOBUTTON,12,212,264,10 + "Button",BS_AUTORADIOBUTTON,12,230,264,10 END IDD_CLOSEDOCUMENTS DIALOGEX 0, 0, 370, 197 @@ -402,10 +404,10 @@ IDD_UPDATE DIALOGEX 0, 0, 196, 138 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "OpenMPT Internet Update" +CAPTION "OpenMPT Update" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "&Update",IDOK,84,120,50,14 + DEFPUSHBUTTON "&Update",IDOK,18,120,116,14 PUSHBUTTON "&Cancel",IDCANCEL,138,120,50,14 LTEXT "A new version of OpenMPT has been released.",IDC_STATIC,6,6,180,12 LTEXT "Your version:",IDC_STATIC,6,24,44,8 @@ -1003,6 +1005,11 @@ 0, 100, 100, 0 END +IDD_UPDATE AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // German (Germany) resources ///////////////////////////////////////////////////////////////////////////// @@ -2738,7 +2745,7 @@ MENUITEM "&OpenMPT Website", ID_NETLINK_MODPLUG MENUITEM "&Web Resources", ID_NETLINK_TOP_PICKS MENUITEM SEPARATOR - MENUITEM "Check for &Updates", ID_INTERNETUPDATE + MENUITEM "Check for &Updates...", ID_INTERNETUPDATE MENUITEM "&About OpenMPT", ID_APP_ABOUT END END Index: mptrack/resource.h =================================================================== --- mptrack/resource.h (revision 13367) +++ mptrack/resource.h (working copy) @@ -981,6 +981,7 @@ #define IDC_STATIC_RECORDING 2513 #define IDC_COMBO_RECORDING_CHANNELS 2514 #define IDC_COMBO_RECORDING_SOURCE 2515 +#define IDC_CHECK_UPDATEINSTALLAUTOMATICALLY 2516 #define ID_FILE_NEWMOD 32771 #define ID_FILE_NEWXM 32772 #define ID_FILE_NEWS3M 32773 @@ -1287,7 +1288,7 @@ #define _APS_3D_CONTROLS 1 #define _APS_NEXT_RESOURCE_VALUE 543 #define _APS_NEXT_COMMAND_VALUE 44646 -#define _APS_NEXT_CONTROL_VALUE 2516 +#define _APS_NEXT_CONTROL_VALUE 2517 #define _APS_NEXT_SYMED_VALUE 901 #endif #endif Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 13367) +++ mptrack/TrackerSettings.cpp (working copy) @@ -312,14 +312,19 @@ , vstHostVendorVersion(conf, U_("VST Plugins"), U_("HostVendorVersion"), Version::Current().GetRawVersion()) // Update , UpdateEnabled(conf, U_("Update"), U_("Enabled"), true) + , UpdateInstallAutomatically(conf, U_("Update"), U_("InstallAutomatically"), false) , UpdateLastUpdateCheck(conf, U_("Update"), U_("LastUpdateCheck"), mpt::Date::Unix(time_t())) , UpdateUpdateCheckPeriod_DEPRECATED(conf, U_("Update"), U_("UpdateCheckPeriod"), 7) , UpdateIntervalDays(conf, U_("Update"), U_("UpdateCheckIntervalDays"), 7) , UpdateChannel(conf, U_("Update"), U_("Channel"), UpdateChannelRelease) +#if MPT_UPDATE_LEGACY , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) , UpdateChannelReleaseURL(conf, U_("Update"), U_("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) , UpdateChannelNextURL(conf, U_("Update"), U_("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) , UpdateChannelDevelopmentURL(conf, U_("Update"), U_("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) +#else // !MPT_UPDATE_LEGACY + , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), U_("https://update.openmpt.org/check/$VERSION/$GUID")) +#endif // MPT_UPDATE_LEGACY , UpdateAPIURL(conf, U_("Update"), U_("APIURL"), CUpdateCheck::GetDefaultAPIURL()) , UpdateStatisticsConsentAsked(conf, U_("Update"), U_("StatistisConsentAsked"), false) , UpdateStatistics(conf, U_("Update"), U_("Statistis"), false) @@ -326,6 +331,9 @@ , UpdateSendGUID_DEPRECATED(conf, U_("Update"), U_("SendGUID"), false) , UpdateShowUpdateHint(conf, U_("Update"), U_("ShowUpdateHint"), true) , UpdateIgnoreVersion(conf, U_("Update"), U_("IgnoreVersion"), _T("")) + , UpdateExperimentalNewAutoUpdate(conf, U_("Update"), U_("ExperimentalNewAutoUpdate"), false) + , UpdateSkipSignatureVerificationUNSECURE(conf, U_("Update"), U_("SkipSignatureVerification"), false) + , UpdateSigningKeysRootAnchors(conf, U_("Update"), U_("SigningKeysRootAnchors"), CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors()) // Wine suppport , WineSupportEnabled(conf, U_("WineSupport"), U_("Enabled"), false) , WineSupportAlwaysRecompile(conf, U_("WineSupport"), U_("AlwaysRecompile"), false) @@ -673,7 +681,9 @@ } else { UpdateChannel = UpdateChannelDevelopment; +#if MPT_UPDATE_LEGACY UpdateChannelDevelopmentURL = url; +#endif // MPT_UPDATE_LEGACY } UpdateStatistics = UpdateSendGUID_DEPRECATED.Get(); conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 13367) +++ mptrack/TrackerSettings.h (working copy) @@ -839,14 +839,17 @@ // Update Setting<bool> UpdateEnabled; + Setting<bool> UpdateInstallAutomatically; Setting<mpt::Date::Unix> UpdateLastUpdateCheck; Setting<int32> UpdateUpdateCheckPeriod_DEPRECATED; Setting<int32> UpdateIntervalDays; Setting<uint32> UpdateChannel; Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; +#if MPT_UPDATE_LEGACY Setting<mpt::ustring> UpdateChannelReleaseURL; Setting<mpt::ustring> UpdateChannelNextURL; Setting<mpt::ustring> UpdateChannelDevelopmentURL; +#endif // MPT_UPDATE_LEGACY Setting<mpt::ustring> UpdateAPIURL; Setting<bool> UpdateStatisticsConsentAsked; Setting<bool> UpdateStatistics; @@ -853,6 +856,9 @@ Setting<bool> UpdateSendGUID_DEPRECATED; Setting<bool> UpdateShowUpdateHint; Setting<CString> UpdateIgnoreVersion; + Setting<bool> UpdateExperimentalNewAutoUpdate; + Setting<bool> UpdateSkipSignatureVerificationUNSECURE; + Setting<std::vector<mpt::ustring>> UpdateSigningKeysRootAnchors; // Wine support Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 13367) +++ mptrack/UpdateCheck.cpp (working copy) @@ -20,14 +20,298 @@ #include "Mainfrm.h" #include "../common/mptThread.h" #include "../common/mptOSError.h" +#include "../common/mptCrypto.h" #include "HTTP.h" #include "../misc/JSON.h" #include "dlg_misc.h" -#include "..//sounddev/SoundDeviceManager.h" +#include "../sounddev/SoundDeviceManager.h" +#include "ProgressDialog.h" +#include "Moddoc.h" OPENMPT_NAMESPACE_BEGIN + + +namespace Update { + + struct windowsversion { + uint64 version_major = 0; + uint64 version_minor = 0; + uint64 servicepack_major = 0; + uint64 servicepack_minor = 0; + uint64 build = 0; + uint64 wine_major = 0; + uint64 wine_minor = 0; + uint64 wine_update = 0; + }; + MPT_JSON_INLINE(Update::windowsversion, { + MPT_JSON_MAP(version_major); + MPT_JSON_MAP(version_minor); + MPT_JSON_MAP(servicepack_major); + MPT_JSON_MAP(servicepack_minor); + MPT_JSON_MAP(build); + MPT_JSON_MAP(wine_major); + MPT_JSON_MAP(wine_minor); + MPT_JSON_MAP(wine_update); + }) + + struct autoupdate_installer { + std::vector<mpt::ustring> arguments = {}; + }; + MPT_JSON_INLINE(Update::autoupdate_installer, { + MPT_JSON_MAP(arguments); + }) + + struct autoupdate_archive { + mpt::ustring subfolder = U_(""); + mpt::ustring restartbinary = U_(""); + }; + MPT_JSON_INLINE(Update::autoupdate_archive, { + MPT_JSON_MAP(subfolder); + MPT_JSON_MAP(restartbinary); + }) + + struct downloadinfo { + mpt::ustring url = U_(""); + std::map<mpt::ustring, mpt::ustring> checksums = {}; + mpt::ustring filename = U_(""); + std::optional<autoupdate_installer> autoupdate_installer; + std::optional<autoupdate_archive> autoupdate_archive; + }; + MPT_JSON_INLINE(Update::downloadinfo, { + MPT_JSON_MAP(url); + MPT_JSON_MAP(checksums); + MPT_JSON_MAP(filename); + MPT_JSON_MAP(autoupdate_installer); + MPT_JSON_MAP(autoupdate_archive); + }) + + struct download { + mpt::ustring url = U_(""); + mpt::ustring type = U_(""); + bool can_autoupdate = false; + mpt::ustring autoupdate_minversion = U_(""); + mpt::ustring os = U_(""); + std::optional<windowsversion> required_windows_version; + std::map<mpt::ustring, bool> required_architectures = {}; + std::map<mpt::ustring, bool> supported_architectures = {}; + std::map<mpt::ustring, std::map<mpt::ustring, bool>> required_processor_features = {}; + }; + MPT_JSON_INLINE(Update::download, { + MPT_JSON_MAP(url); + MPT_JSON_MAP(type); + MPT_JSON_MAP(can_autoupdate); + MPT_JSON_MAP(autoupdate_minversion); + MPT_JSON_MAP(os); + MPT_JSON_MAP(required_windows_version); + MPT_JSON_MAP(required_architectures); + MPT_JSON_MAP(supported_architectures); + MPT_JSON_MAP(required_processor_features); + }) + + struct versioninfo { + mpt::ustring version = U_(""); + mpt::ustring date = U_(""); + mpt::ustring announcement_url = U_(""); + mpt::ustring changelog_url = U_(""); + std::map<mpt::ustring, download> downloads = {}; + }; + MPT_JSON_INLINE(Update::versioninfo, { + MPT_JSON_MAP(version); + MPT_JSON_MAP(date); + MPT_JSON_MAP(announcement_url); + MPT_JSON_MAP(changelog_url); + MPT_JSON_MAP(downloads); + }) + + using versions = std::map<mpt::ustring, versioninfo>; + +} // namespace Update + + +struct UpdateInfo { + mpt::ustring version; + mpt::ustring download; + bool IsAvailable() const + { + return !version.empty(); + } +}; + +static bool IsCurrentArchitecture(const mpt::ustring &architecture) +{ + return mpt::Windows::Name(mpt::Windows::GetProcessArchitecture()) == architecture; +} + +static bool IsArchitectureSupported(const mpt::ustring &architecture) +{ + const auto & architectures = mpt::Windows::GetSupportedProcessArchitectures(mpt::Windows::GetHostArchitecture()); + for(const auto & arch : architectures) + { + if(mpt::Windows::Name(arch) == architecture) + { + return true; + } + } + return false; +} + +static bool IsArchitectureFeatureSupported(const mpt::ustring &architecture, const mpt::ustring &feature) +{ + MPT_UNUSED_VARIABLE(architecture); + #ifdef ENABLE_ASM + if(feature == U_("")) return true; + else if(feature == U_("lm")) return (CPU::GetAvailableFeatures() & CPU::feature::lm) != 0; + else if(feature == U_("mmx")) return (CPU::GetAvailableFeatures() & CPU::feature::mmx) != 0; + else if(feature == U_("sse")) return (CPU::GetAvailableFeatures() & CPU::feature::sse) != 0; + else if(feature == U_("sse2")) return (CPU::GetAvailableFeatures() & CPU::feature::sse2) != 0; + else if(feature == U_("sse3")) return (CPU::GetAvailableFeatures() & CPU::feature::sse3) != 0; + else if(feature == U_("ssse3")) return (CPU::GetAvailableFeatures() & CPU::feature::ssse3) != 0; + else if(feature == U_("sse4.1")) return (CPU::GetAvailableFeatures() & CPU::feature::sse4_1) != 0; + else if(feature == U_("sse4.2")) return (CPU::GetAvailableFeatures() & CPU::feature::sse4_2) != 0; + else if(feature == U_("avx")) return (CPU::GetAvailableFeatures() & CPU::feature::avx) != 0; + else if(feature == U_("avx2")) return (CPU::GetAvailableFeatures() & CPU::feature::avx2) != 0; + else return false; + #else + return true; + #endif +} + + +static mpt::ustring GetChannelName(UpdateChannel channel) +{ + mpt::ustring channelName = U_("release"); + switch(channel) + { + case UpdateChannelDevelopment: + channelName = U_("development"); + break; + case UpdateChannelNext: + channelName = U_("next"); + break; + case UpdateChannelRelease: + channelName = U_("release"); + break; + default: + channelName = U_("release"); + break; + } + return channelName; +} + + +static UpdateInfo GetBestDownload(const Update::versions &versions) +{ + + UpdateInfo result; + VersionWithRevision bestVersion = VersionWithRevision::Current(); + + for(const auto & [versionname, versioninfo] : versions) + { + + if(!VersionWithRevision::Parse(versioninfo.version).IsNewerThan(bestVersion)) + { + continue; + } + + mpt::ustring bestDownloadName; + + // check if version supports the current system + bool is_supported = false; + for(auto & [downloadname, download] : versioninfo.downloads) + { + + // is it for windows? + if(download.os != U_("windows") || !download.required_windows_version) + { + continue; + } + + // can the installer run on the current system? + bool download_supported = true; + for(const auto & [architecture, required] : download.required_architectures) + { + if(!(required && IsArchitectureSupported(architecture))) + { + download_supported = false; + } + } + + // does the download run on current architecture? + bool architecture_supported = false; + for(const auto & [architecture, supported] : download.supported_architectures) + { + if(supported && IsCurrentArchitecture(architecture)) + { + architecture_supported = true; + } + } + if(!architecture_supported) + { + download_supported = false; + } + + // does the current system have all required features? + for(const auto & [architecture, features] : download.required_processor_features) + { + if(IsCurrentArchitecture(architecture)) + { + for(const auto & [feature, required] : features) + { + if(!(required && IsArchitectureFeatureSupported(architecture, feature))) + { + download_supported = false; + } + } + } + } + + if(mpt::Windows::Version::Current().IsBefore( + mpt::Windows::Version::System(mpt::saturate_cast<uint32>(download.required_windows_version->version_major), mpt::saturate_cast<uint32>(download.required_windows_version->version_minor)), + mpt::Windows::Version::ServicePack(mpt::saturate_cast<uint16>(download.required_windows_version->servicepack_major), mpt::saturate_cast<uint16>(download.required_windows_version->servicepack_minor)), + mpt::Windows::Version::Build(mpt::saturate_cast<uint32>(download.required_windows_version->build)) + )) + { + download_supported = false; + } + + if(mpt::Windows::IsWine() && theApp.GetWineVersion()->Version().IsValid()) + { + if(theApp.GetWineVersion()->Version().IsBefore(mpt::Wine::Version(mpt::saturate_cast<uint8>(download.required_windows_version->wine_major), mpt::saturate_cast<uint8>(download.required_windows_version->wine_minor), mpt::saturate_cast<uint8>(download.required_windows_version->wine_update)))) + { + download_supported = false; + } + } + + if(download_supported) + { + is_supported = true; + if(theApp.IsInstallerMode() && download.type == U_("installer")) + { + bestDownloadName = downloadname; + } else if(theApp.IsPortableMode() && download.type == U_("archive")) + { + bestDownloadName = downloadname; + } + } + + } + + if(is_supported) + { + bestVersion = VersionWithRevision::Parse(versioninfo.version); + result.version = versionname; + result.download = bestDownloadName; + } + + } + + return result; + +} + + // Update notification dialog class UpdateDialog : public CDialog { @@ -35,14 +319,16 @@ const CString m_releaseVersion; const CString m_releaseDate; const CString m_releaseURL; + const CString m_buttonText; CFont m_boldFont; public: - UpdateDialog(const CString &releaseVersion, const CString &releaseDate, const CString &releaseURL) + UpdateDialog(const CString &releaseVersion, const CString &releaseDate, const CString &releaseURL, const CString &buttonText = _T("&Update")) : CDialog(IDD_UPDATE) , m_releaseVersion(releaseVersion) , m_releaseDate(releaseDate) , m_releaseURL(releaseURL) + , m_buttonText(buttonText) { } BOOL OnInitDialog() override @@ -49,6 +335,8 @@ { CDialog::OnInitDialog(); + SetDlgItemText(IDOK, m_buttonText); + CFont *font = GetDlgItem(IDC_VERSION2)->GetFont(); LOGFONT lf; font->GetLogFont(&lf); @@ -56,7 +344,7 @@ m_boldFont.CreateFontIndirect(&lf); GetDlgItem(IDC_VERSION2)->SetFont(&m_boldFont); - SetDlgItemText(IDC_VERSION1, mpt::cfmt::val(Version::Current())); + SetDlgItemText(IDC_VERSION1, mpt::cfmt::val(VersionWithRevision::Current())); SetDlgItemText(IDC_VERSION2, m_releaseVersion); SetDlgItemText(IDC_DATE, m_releaseDate); SetDlgItemText(IDC_SYSLINK1, _T("More information about this build:\n<a href=\"") + m_releaseURL + _T("\">") + m_releaseURL + _T("</a>")); @@ -103,6 +391,8 @@ } +#if MPT_UPDATE_LEGACY + mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() { return U_("https://update.openmpt.org/check/$VERSION/$GUID"); @@ -118,7 +408,21 @@ return U_("https://update.openmpt.org/check/testing/$VERSION/$GUID"); } +#endif // MPT_UPDATE_LEGACY + +std::vector<mpt::ustring> CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors() +{ + // IMPORTANT: + // Signing keys are *NOT* stored on the same server as openmpt.org or the updates themselves, + // because otherwise, a single compromised server could allow for rogue updates. + return { + U_("https://sagamusix.de/openmpt-update/"), + U_("https://manx.datengang.de/openmpt/update/") + }; +} + + mpt::ustring CUpdateCheck::GetDefaultAPIURL() { return U_("https://update.openmpt.org/api/v3/"); @@ -134,9 +438,18 @@ } + +bool CUpdateCheck::IsSuitableUpdateMoment() +{ + const auto documents = theApp.GetOpenDocuments(); + return std::all_of(documents.begin(), documents.end(), [](auto doc) { return !doc->IsModified(); }); +} + + // Start update check void CUpdateCheck::StartUpdateCheckAsync(bool isAutoUpdate) { + bool loadPersisted = false; if(isAutoUpdate) { if(!TrackerSettings::Instance().UpdateEnabled) @@ -143,6 +456,10 @@ { return; } + if(!IsSuitableUpdateMoment()) + { + return; + } int updateCheckPeriod = TrackerSettings::Instance().UpdateIntervalDays; if(updateCheckPeriod < 0) { @@ -155,7 +472,15 @@ const double secsSinceLastCheck = difftime(now, lastCheck); if(secsSinceLastCheck > 0.0 && secsSinceLastCheck < updateCheckPeriod * 86400.0) { - return; +#if MPT_UPDATE_LEGACY + if(!TrackerSettings::Instance().UpdateExperimentalNewAutoUpdate) + { + return; + } else +#endif // MPT_UPDATE_LEGACY + { + loadPersisted = true; + } } // Never ran update checks before, so we notify the user of automatic update checks. @@ -169,7 +494,7 @@ checkIntervalDays == 1 ? CString(_T("every day")) : MPT_CFORMAT("every {} days")(checkIntervalDays) ); - if(Reporting::Confirm(msg, _T("OpenMPT Internet Update")) == cnfNo) + if(Reporting::Confirm(msg, _T("OpenMPT Update")) == cnfNo) { TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(now); return; @@ -177,9 +502,14 @@ } } else { + if(!IsSuitableUpdateMoment()) + { + Reporting::Notification(_T("Please save all modified modules before updating OpenMPT."), _T("OpenMPT Update")); + return; + } if(!TrackerSettings::Instance().UpdateEnabled) { - if(Reporting::Confirm(_T("Update Check is disabled. Do you want to check anyway?"), _T("OpenMPT Internet Update")) != cnfYes) + if(Reporting::Confirm(_T("Update Check is disabled. Do you want to check anyway?"), _T("OpenMPT Update")) != cnfYes) { return; } @@ -207,10 +537,13 @@ CUpdateCheck::Context context; context.window = CMainFrame::GetMainFrame(); + context.msgStart = MPT_WM_APP_UPDATECHECK_START; context.msgProgress = MPT_WM_APP_UPDATECHECK_PROGRESS; + context.msgCanceled = MPT_WM_APP_UPDATECHECK_CANCELED; + context.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; context.msgSuccess = MPT_WM_APP_UPDATECHECK_SUCCESS; - context.msgFailure = MPT_WM_APP_UPDATECHECK_FAILURE; context.autoUpdate = isAutoUpdate; + context.loadPersisted = loadPersisted; context.statistics = GetStatisticsDataV3(CUpdateCheck::Settings()); std::thread(CUpdateCheck::ThreadFunc(CUpdateCheck::Settings(), context)).detach(); } @@ -218,10 +551,14 @@ CUpdateCheck::Settings::Settings() : periodDays(TrackerSettings::Instance().UpdateIntervalDays) - , channel(TrackerSettings::Instance().UpdateChannel) + , channel(static_cast<UpdateChannel>(TrackerSettings::Instance().UpdateChannel.Get())) + , persistencePath(theApp.GetConfigPath()) +#if MPT_UPDATE_LEGACY + , modeLegacy(!TrackerSettings::Instance().UpdateExperimentalNewAutoUpdate) , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) +#endif // MPT_UPDATE_LEGACY , apiURL(TrackerSettings::Instance().UpdateAPIURL) , sendStatistics(TrackerSettings::Instance().UpdateStatistics) , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) @@ -240,7 +577,7 @@ void CUpdateCheck::ThreadFunc::operator () () { mpt::SetCurrentThreadPriority(context.autoUpdate ? mpt::ThreadPriorityLower : mpt::ThreadPriorityNormal); - CUpdateCheck::CheckForUpdate(settings, context); + CheckForUpdate(settings, context); } @@ -248,7 +585,6 @@ { JSON::value j; j["OpenMPT"]["Version"] = mpt::ufmt::val(Version::Current()); - j["OpenMPT"]["BuildVariant"] = BuildVariants().GuessCurrentBuildName(); j["OpenMPT"]["Architecture"] = mpt::Windows::Name(mpt::Windows::GetProcessArchitecture()); j["Update"]["PeriodDays"] = settings.periodDays; j["System"]["Windows"]["Version"]["Name"] = mpt::Windows::Version::Current().GetName(); @@ -315,6 +651,7 @@ } +#if MPT_UPDATE_LEGACY mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) { mpt::ustring updateURL; @@ -360,24 +697,126 @@ updateURL = mpt::String::Replace(updateURL, U_("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : U_("anonymous")); return updateURL; } +#endif // MPT_UPDATE_LEGACY // Run update check (independent thread) -CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Settings &settings, const std::string &statistics) +CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Context &context, const CUpdateCheck::Settings &settings, const std::string &statistics) { - + CUpdateCheck::Result result; + if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 0)) + { + throw CUpdateCheck::Cancel(); + } + if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 20)) + { + throw CUpdateCheck::Cancel(); + } HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 40)) + { + throw CUpdateCheck::Cancel(); + } +#if MPT_UPDATE_LEGACY + if(settings.modeLegacy) + { + result = SearchUpdateLegacy(internet, settings); + } else +#endif // MPT_UPDATE_LEGACY + { + bool loaded = false; + if(context.loadPersisted) + { + try + { + InputFile f(settings.persistencePath + P_("update-") + mpt::PathString::FromUnicode(GetChannelName(settings.channel)) + P_(".json")); + if(f.IsValid()) + { + std::vector<std::byte> data = GetFileReader(f).ReadRawDataAsByteVector(); + nlohmann::json::parse(mpt::buffer_cast<std::string>(data)).get<Update::versions>(); + result.CheckTime = time_t{}; + result.json = data; + loaded = true; + } + } catch(mpt::out_of_memory e) + { + mpt::delete_out_of_memory(e); + } catch(const std::exception &) + { + // ignore + } + } + if(!loaded) + { + result = SearchUpdateModern(internet, settings); + } + try + { + { + mpt::SafeOutputFile f(settings.persistencePath + P_("update-") + mpt::PathString::FromUnicode(GetChannelName(settings.channel)) + P_(".json"), std::ios::binary); + f.stream().imbue(std::locale::classic()); + mpt::IO::WriteRaw(f.stream(), mpt::as_span(result.json)); + f.stream().flush(); + } + } catch(mpt::out_of_memory e) + { + mpt::delete_out_of_memory(e); + } catch(const std::exception &) + { + // ignore + } + } + if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 60)) + { + throw CUpdateCheck::Cancel(); + } + SendStatistics(internet, settings, statistics); + if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 80)) + { + throw CUpdateCheck::Cancel(); + } + CleanOldUpdates(settings, context); + if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 100)) + { + throw CUpdateCheck::Cancel(); + } + return result; +} - // Establish a connection. - HTTP::Request request; - request.SetURI(ParseURI(GetUpdateURLV2(settings))); - request.method = HTTP::Method::Get; - request.flags = HTTP::NoCache; - HTTP::Result resultHTTP = internet(request); +void CUpdateCheck::CleanOldUpdates(const CUpdateCheck::Settings & /* settings */ , const CUpdateCheck::Context & /* context */ ) +{ + mpt::PathString dirTemp = mpt::GetTempDirectory(); + if(dirTemp.empty()) + { + return; + } + if(PathIsRelative(dirTemp.AsNative().c_str())) + { + return; + } + if(!dirTemp.IsDirectory()) + { + return; + } + mpt::PathString dirTempOpenMPT = dirTemp + P_("OpenMPT") + mpt::PathString::FromNative(mpt::RawPathString(1, mpt::PathString::GetDefaultPathSeparator())); + mpt::PathString dirTempOpenMPTUpdates = dirTempOpenMPT + P_("Updates") + mpt::PathString::FromNative(mpt::RawPathString(1, mpt::PathString::GetDefaultPathSeparator())); + mpt::DeleteWholeDirectoryTree(dirTempOpenMPTUpdates); +} + +void CUpdateCheck::SendStatistics(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings, const std::string &statistics) +{ if(settings.sendStatistics) { + if(!settings.modeLegacy) + { + HTTP::Request requestLegacyUpdate; + requestLegacyUpdate.SetURI(ParseURI(GetUpdateURLV2(settings))); + requestLegacyUpdate.method = HTTP::Method::Get; + requestLegacyUpdate.flags = HTTP::NoCache; + HTTP::Result resultLegacyUpdateHTTP = internet(requestLegacyUpdate); + } HTTP::Request requestStatistics; if(settings.statisticsUUID.IsValid()) { @@ -395,7 +834,20 @@ requestStatistics.data = mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(jsondata)); internet(requestStatistics); } +} + +#if MPT_UPDATE_LEGACY +CUpdateCheck::Result CUpdateCheck::SearchUpdateLegacy(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings) +{ + + HTTP::Request request; + request.SetURI(ParseURI(GetUpdateURLV2(settings))); + request.method = HTTP::Method::Get; + request.flags = HTTP::NoCache; + + HTTP::Result resultHTTP = internet(request); + // Retrieve HTTP status code. if(resultHTTP.Status >= 400) { @@ -439,21 +891,61 @@ } result.UpdateAvailable = true; } + return result; + } +#endif // MPT_UPDATE_LEGACY +CUpdateCheck::Result CUpdateCheck::SearchUpdateModern(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings) +{ + + HTTP::Request request; + request.SetURI(ParseURI(settings.apiURL + MPT_UFORMAT("update/{}")(GetChannelName(static_cast<UpdateChannel>(settings.channel))))); + request.method = HTTP::Method::Get; + request.acceptMimeTypes = HTTP::MimeTypes::JSON(); + request.flags = HTTP::NoCache; + + HTTP::Result resultHTTP = internet(request); + + // Retrieve HTTP status code. + if(resultHTTP.Status >= 400) + { + throw CUpdateCheck::Error(MPT_CFORMAT("Version information could not be found on the server (HTTP status code {}). Maybe your version of OpenMPT is too old!")(resultHTTP.Status)); + } + + // Now, evaluate the downloaded data. + CUpdateCheck::Result result; + result.CheckTime = time(nullptr); + try + { + nlohmann::json::parse(mpt::buffer_cast<std::string>(resultHTTP.Data)).get<Update::versions>(); + result.json = resultHTTP.Data; + } catch(mpt::out_of_memory e) + { + mpt::rethrow_out_of_memory(e); + } catch(const nlohmann::json::exception &e) + { + throw CUpdateCheck::Error(MPT_CFORMAT("Could not understand server response ({}). Maybe your version of OpenMPT is too old!")(mpt::get_exception_text<mpt::ustring>(e))); + } + + return result; + +} + + void CUpdateCheck::CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context) { // incremented before starting the thread MPT_ASSERT(s_InstanceCount.load() >= 1); CUpdateCheck::Result result; - context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, s_InstanceCount.load()); try { + context.window->SendMessage(context.msgStart, context.autoUpdate ? 1 : 0, 0); try { - result = SearchUpdate(settings, context.statistics); + result = SearchUpdate(context, settings, context.statistics); } catch(const bad_uri &e) { throw CUpdateCheck::Error(MPT_CFORMAT("Error parsing update URL: {}")(mpt::get_exception_text<CString>(e))); @@ -461,6 +953,12 @@ { throw CUpdateCheck::Error(CString(_T("HTTP error: ")) + mpt::ToCString(e.GetMessage())); } + } catch(const CUpdateCheck::Cancel &) + { + context.window->SendMessage(context.msgCanceled, context.autoUpdate ? 1 : 0, 0); + s_InstanceCount.fetch_sub(1); + MPT_ASSERT(s_InstanceCount.load() >= 0); + return; } catch(const CUpdateCheck::Error &e) { context.window->SendMessage(context.msgFailure, context.autoUpdate ? 1 : 0, reinterpret_cast<LPARAM>(&e)); @@ -474,6 +972,12 @@ } +bool CUpdateCheck::IsAutoUpdateFromMessage(WPARAM wparam, LPARAM /* lparam */ ) +{ + return wparam ? true : false; +} + + CUpdateCheck::Result CUpdateCheck::ResultFromMessage(WPARAM /*wparam*/ , LPARAM lparam) { const CUpdateCheck::Result &result = *reinterpret_cast<CUpdateCheck::Result*>(lparam); @@ -488,24 +992,554 @@ } + +static const char * const updateScript = R"vbs( + +Wscript.Echo +Wscript.Echo "OpenMPT portable Update" +Wscript.Echo "=======================" + +Wscript.Echo "[ 0%] Waiting for OpenMPT to close..." +WScript.Sleep 2000 + +Wscript.Echo "[ 10%] Loading update settings..." +zip = WScript.Arguments.Item(0) +subfolder = WScript.Arguments.Item(1) +dst = WScript.Arguments.Item(2) +restartbinary = WScript.Arguments.Item(3) + +Wscript.Echo "[ 20%] Preparing update..." +Set fso = CreateObject("Scripting.FileSystemObject") +Set shell = CreateObject("Wscript.Shell") +Set application = CreateObject("Shell.Application") + +Sub CreateFolder(pathname) + If Not fso.FolderExists(pathname) Then + fso.CreateFolder pathname + End If +End Sub + +Sub DeleteFolder(pathname) + If fso.FolderExists(pathname) Then + fso.DeleteFolder pathname + End If +End Sub + +Sub UnZIP(zipfilename, destinationfolder) + If Not fso.FolderExists(destinationfolder) Then + fso.CreateFolder(destinationfolder) + End If + application.NameSpace(destinationfolder).Copyhere application.NameSpace(zipfilename).Items, 16+256 +End Sub + +Wscript.Echo "[ 30%] Changing to temporary directory..." +shell.CurrentDirectory = fso.GetParentFolderName(WScript.ScriptFullName) + +Wscript.Echo "[ 40%] Decompressing update..." +UnZIP zip, fso.BuildPath(fso.GetAbsolutePathName("."), "tmp") + +Wscript.Echo "[ 60%] Installing update..." +If subfolder = "" Or subfolder = "." Then + fso.CopyFolder fso.BuildPath(fso.GetAbsolutePathName("."), "tmp"), dst, True +Else + fso.CopyFolder fso.BuildPath(fso.BuildPath(fso.GetAbsolutePathName("."), "tmp"), subfolder), dst, True +End If + +Wscript.Echo "[ 80%] Deleting temporary directory..." +DeleteFolder fso.BuildPath(fso.GetAbsolutePathName("."), "tmp") + +Wscript.Echo "[ 90%] Restarting OpenMPT..." +application.ShellExecute fso.BuildPath(dst, restartbinary), , dst, , 10 + +Wscript.Echo "[100%] Update successful!" +Wscript.Echo +WScript.Sleep 1000 + +Wscript.Echo "Closing update window in 5 seconds..." +WScript.Sleep 1000 +Wscript.Echo "Closing update window in 4 seconds..." +WScript.Sleep 1000 +Wscript.Echo "Closing update window in 3 seconds..." +WScript.Sleep 1000 +Wscript.Echo "Closing update window in 2 seconds..." +WScript.Sleep 1000 +Wscript.Echo "Closing update window in 1 seconds..." +WScript.Sleep 1000 +Wscript.Echo "Closing update window..." + +WScript.Quit + +)vbs"; + + + +class CDoUpdate: public CProgressDialog +{ +private: + Update::download download; + class Aborted : public std::exception {}; + class Warning : public std::exception + { + private: + mpt::ustring msg; + public: + Warning(const mpt::ustring &msg_) + : msg(msg_) + { + return; + } + mpt::ustring get_msg() const + { + return msg; + } + }; + class Error : public std::exception + { + private: + mpt::ustring msg; + public: + Error(const mpt::ustring &msg_) + : msg(msg_) + { + return; + } + mpt::ustring get_msg() const + { + return msg; + } + }; +public: + CDoUpdate(Update::download download, CWnd *parent = NULL) + : CProgressDialog(parent) + , download(download) + { + return; + } + void UpdateProgress(const CString &text, double percent) + { + SetText(text); + SetProgress(static_cast<uint64>(percent * 100.0)); + ProcessMessages(); + if(m_abort) + { + throw Aborted(); + } + } + void Run() override + { + try + { + SetTitle(_T("OpenMPT Update")); + SetAbortText(_T("Cancel")); + SetText(_T("OpenMPT Update")); + SetRange(0, 10000); + ProcessMessages(); + + Update::downloadinfo downloadinfo; + mpt::PathString dirTempOpenMPTUpdates; + mpt::PathString updateFilename; + { + + UpdateProgress(_T("Connecting..."), 0.0); + HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); + + UpdateProgress(_T("Downloading update information..."), 1.0); + std::vector<std::byte> rawDownloadInfo; + { + HTTP::Request request; + request.SetURI(ParseURI(download.url)); + request.method = HTTP::Method::Get; + request.acceptMimeTypes = HTTP::MimeTypes::JSON(); + HTTP::Result resultHTTP = internet(request); + if(resultHTTP.Status != 200) + { + throw Error(MPT_UFORMAT("Error downloading update information: HTTP status {}.")(resultHTTP.Status)); + } + rawDownloadInfo = std::move(resultHTTP.Data); + } + + if(!TrackerSettings::Instance().UpdateSkipSignatureVerificationUNSECURE) + { + std::vector<std::byte> rawSignature; + UpdateProgress(_T("Retrieving update signature..."), 2.0); + { + HTTP::Request request; + request.SetURI(ParseURI(download.url + U_(".jws.json"))); + request.method = HTTP::Method::Get; + request.acceptMimeTypes = HTTP::MimeTypes::JSON(); + HTTP::Result resultHTTP = internet(request); + if(resultHTTP.Status != 200) + { + throw Error(MPT_UFORMAT("Error downloading update signature: HTTP status {}.")(resultHTTP.Status)); + } + rawSignature = std::move(resultHTTP.Data); + } + UpdateProgress(_T("Retrieving update signing public keys..."), 3.0); + std::vector<mpt::crypto::asymmetric::rsassa_pss<>::public_key> keys; + { + std::vector<mpt::ustring> keyAnchors = TrackerSettings::Instance().UpdateSigningKeysRootAnchors; + if(keyAnchors.empty()) + { + Reporting::Warning(U_("Warning: No update signing public key root anchors configured. Update cannot be verified."), U_("OpenMPT Update")); + } + for(const auto & keyAnchor : keyAnchors) + { + HTTP::Request request; + request.SetURI(ParseURI(keyAnchor + U_("signingkeys.jwkset.json"))); + request.method = HTTP::Method::Get; + request.flags = HTTP::NoCache; + request.acceptMimeTypes = HTTP::MimeTypes::JSON(); + try + { + HTTP::Result resultHTTP = internet(request); + resultHTTP.CheckStatus(200); + mpt::append(keys, mpt::crypto::asymmetric::rsassa_pss<>::parse_jwk_set(mpt::ToUnicode(mpt::Charset::UTF8, mpt::buffer_cast<std::string>(resultHTTP.Data)))); + } catch(mpt::out_of_memory e) + { + mpt::rethrow_out_of_memory(e); + } catch(const std::exception &e) + { + Reporting::Warning(MPT_UFORMAT("Warning: Retrieving update signing public keys from {} failed: {}")(keyAnchor, mpt::get_exception_text<mpt::ustring>(e)), U_("OpenMPT Update")); + } catch(...) + { + Reporting::Warning(MPT_UFORMAT("Warning: Retrieving update signing public keys from {} failed.")(keyAnchor), U_("OpenMPT Update")); + } + } + } + if(keys.empty()) + { + throw Error(U_("Error retrieving update signing public keys.")); + } + UpdateProgress(_T("Verifying signature..."), 4.0); + std::vector<std::byte> expectedPayload = mpt::buffer_cast<std::vector<std::byte>>(rawDownloadInfo); + mpt::ustring signature = mpt::ToUnicode(mpt::Charset::UTF8, mpt::buffer_cast<std::string>(rawSignature)); + + mpt::crypto::asymmetric::rsassa_pss<>::jws_verify_at_least_one(keys, expectedPayload, signature); + + } + + UpdateProgress(_T("Parsing update information..."), 5.0); + try + { + downloadinfo = nlohmann::json::parse(mpt::buffer_cast<std::string>(rawDownloadInfo)).get<Update::downloadinfo>(); + } catch(const nlohmann::json::exception &e) + { + throw Error(MPT_UFORMAT("Error parsing update information: {}.")(mpt::get_exception_text<mpt::ustring>(e))); + } + + UpdateProgress(_T("Preparing download..."), 6.0); + mpt::PathString dirTemp = mpt::GetTempDirectory(); + mpt::PathString dirTempOpenMPT = dirTemp + P_("OpenMPT") + mpt::PathString::FromNative(mpt::RawPathString(1, mpt::PathString::GetDefaultPathSeparator())); + dirTempOpenMPTUpdates = dirTempOpenMPT + P_("Updates") + mpt::PathString::FromNative(mpt::RawPathString(1, mpt::PathString::GetDefaultPathSeparator())); + updateFilename = dirTempOpenMPTUpdates + mpt::PathString::FromUnicode(downloadinfo.filename); + ::CreateDirectory(dirTempOpenMPT.AsNativePrefixed().c_str(), NULL); + ::CreateDirectory(dirTempOpenMPTUpdates.AsNativePrefixed().c_str(), NULL); + + { + + UpdateProgress(_T("Creating file..."), 7.0); + mpt::SafeOutputFile file(updateFilename, std::ios::binary); + file.stream().imbue(std::locale::classic()); + file.stream().exceptions(std::ios::failbit | std::ios::badbit); + + UpdateProgress(_T("Downloading update..."), 8.0); + HTTP::Request request; + request.SetURI(ParseURI(downloadinfo.url)); + request.method = HTTP::Method::Get; + request.acceptMimeTypes = HTTP::MimeTypes::Binary(); + request.outputStream = &file.stream(); + request.progressCallback = [&](HTTP::Progress progress, uint64 transferred, std::optional<uint64> expectedSize) { + switch(progress) + { + case HTTP::Progress::Start: + SetProgress(900); + break; + case HTTP::Progress::ConnectionEstablished: + SetProgress(1000); + break; + case HTTP::Progress::RequestOpened: + SetProgress(1100); + break; + case HTTP::Progress::RequestSent: + SetProgress(1200); + break; + case HTTP::Progress::ResponseReceived: + SetProgress(1300); + break; + case HTTP::Progress::TransferBegin: + SetProgress(1400); + break; + case HTTP::Progress::TransferRunning: + if(expectedSize && ((*expectedSize) != 0)) + { + SetProgress(static_cast<int64>((static_cast<double>(transferred) / static_cast<double>(*expectedSize)) * (10000.0-1500.0-400.0) + 1500.0)); + } else + { + SetProgress((1500 + 9600) / 2); + } + break; + case HTTP::Progress::TransferDone: + SetProgress(9600); + break; + } + ProcessMessages(); + if(m_abort) + { + throw HTTP::Abort(); + } + }; + HTTP::Result resultHTTP = internet(request); + if(resultHTTP.Status != 200) + { + throw Error(MPT_UFORMAT("Error downloading update: HTTP status {}.")(resultHTTP.Status)); + } + } + + UpdateProgress(_T("Disconnecting..."), 97.0); + } + + UpdateProgress(_T("Verifying download..."), 98.0); + bool verified = false; + for(const auto & [algorithm, value] : downloadinfo.checksums) + { + if(algorithm == U_("SHA-512")) + { + std::vector<std::byte> binhash = Util::HexToBin(value); + if(binhash.size() != 512/8) + { + throw Error(U_("Download verification failed.")); + } + std::array<std::byte, 512/8> expected; + std::copy(binhash.begin(), binhash.end(), expected.begin()); + mpt::crypto::hash::SHA512 hash; + mpt::ifstream f(updateFilename, std::ios::binary); + f.imbue(std::locale::classic()); + f.exceptions(std::ios::badbit); + while(!mpt::IO::IsEof(f)) + { + std::array<std::byte, mpt::IO::BUFFERSIZE_TINY> buf; + hash.process(mpt::IO::ReadRaw(f, mpt::as_span(buf))); + } + std::array<std::byte, 512/8> gotten = hash.result(); + if(gotten != expected) + { + throw Error(U_("Download verification failed.")); + } + verified = true; + } + } + if(!verified) + { + throw Error(U_("Error verifying update: No suitable checksum found.")); + } + + UpdateProgress(_T("Installing update..."), 99.0); + bool wantClose = false; + if(download.can_autoupdate && (Version::Current() >= Version::Parse(download.autoupdate_minversion))) + { + if(download.type == U_("installer") && downloadinfo.autoupdate_installer) + { + if(theApp.IsSourceTreeMode()) + { + throw Warning(MPT_UFORMAT("Refusing to launch update '{} {}' when running from source tree.")(updateFilename, mpt::String::Combine(downloadinfo.autoupdate_installer->arguments, U_(" ")))); + } + if(reinterpret_cast<INT_PTR>(ShellExecute(NULL, NULL, + updateFilename.AsNative().c_str(), + mpt::ToWin(mpt::String::Combine(downloadinfo.autoupdate_installer->arguments, U_(" "))).c_str(), + dirTempOpenMPTUpdates.AsNative().c_str(), + SW_SHOWDEFAULT)) < 32) + { + throw Error(U_("Error launching update.")); + } + } else if(download.type == U_("archive") && downloadinfo.autoupdate_archive) + { + try + { + mpt::SafeOutputFile file(dirTempOpenMPTUpdates + P_("update.vbs"), std::ios::binary); + file.stream().imbue(std::locale::classic()); + file.stream().exceptions(std::ios::failbit | std::ios::badbit); + mpt::IO::WriteRaw(file.stream(), mpt::as_span(std::string(updateScript))); + } catch(...) + { + throw Error(U_("Error creating update script.")); + } + std::vector<mpt::ustring> arguments; + arguments.push_back(U_("\"") + (dirTempOpenMPTUpdates + P_("update.vbs")).ToUnicode() + U_("\"")); + arguments.push_back(U_("\"") + updateFilename.ToUnicode() + U_("\"")); + arguments.push_back(U_("\"") + (downloadinfo.autoupdate_archive->subfolder.empty() ? U_(".") : downloadinfo.autoupdate_archive->subfolder) + U_("\"")); + arguments.push_back(U_("\"") + theApp.GetInstallPath().WithoutTrailingSlash().ToUnicode() + U_("\"")); + arguments.push_back(U_("\"") + downloadinfo.autoupdate_archive->restartbinary + U_("\"")); + if(theApp.IsSourceTreeMode()) + { + throw Warning(MPT_UFORMAT("Refusing to launch update '{} {}' when running from source tree.")(P_("cscript.exe"), mpt::String::Combine(arguments, U_(" ")))); + } + if(reinterpret_cast<INT_PTR>(ShellExecute(NULL, NULL, + P_("cscript.exe").AsNative().c_str(), + mpt::ToWin(mpt::String::Combine(arguments, U_(" "))).c_str(), + dirTempOpenMPTUpdates.AsNative().c_str(), + SW_SHOWDEFAULT)) < 32) + { + throw Error(U_("Error launching update.")); + } + wantClose = true; + } else + { + CTrackApp::OpenDirectory(dirTempOpenMPTUpdates); + wantClose = true; + } + } else + { + CTrackApp::OpenDirectory(dirTempOpenMPTUpdates); + wantClose = true; + } + UpdateProgress(_T("Waiting for installer..."), 100.0); + if(wantClose) + { + CMainFrame::GetMainFrame()->PostMessage(WM_QUIT, 0, 0); + } + EndDialog(IDOK); + } catch(mpt::out_of_memory e) + { + mpt::delete_out_of_memory(e); + Reporting::Error(U_("Not enough memory to install update."), U_("OpenMPT Update Error")); + EndDialog(IDCANCEL); + return; + } catch(const HTTP::Abort &) + { + EndDialog(IDCANCEL); + return; + } catch(const Aborted &) + { + EndDialog(IDCANCEL); + return; + } catch(const Warning &e) + { + Reporting::Warning(e.get_msg(), U_("OpenMPT Update")); + EndDialog(IDCANCEL); + return; + } catch(const Error &e) + { + Reporting::Error(e.get_msg(), U_("OpenMPT Update Error")); + EndDialog(IDCANCEL); + return; + } catch(const std::exception &e) + { + Reporting::Error(MPT_UFORMAT("Error installing update: {}")(mpt::get_exception_text<mpt::ustring>(e)), U_("OpenMPT Update Error")); + EndDialog(IDCANCEL); + return; + } catch(...) + { + Reporting::Error(U_("Error installing update."), U_("OpenMPT Update Error")); + EndDialog(IDCANCEL); + return; + } + } +}; + + void CUpdateCheck::ShowSuccessGUI(WPARAM wparam, LPARAM lparam) { + const CUpdateCheck::Result &result = *reinterpret_cast<CUpdateCheck::Result*>(lparam); bool autoUpdate = wparam != 0; - if(result.UpdateAvailable && (!autoUpdate || result.Version != TrackerSettings::Instance().UpdateIgnoreVersion)) + + if(result.CheckTime != time_t{}) { - UpdateDialog dlg(result.Version, result.Date, result.URL); - if(dlg.DoModal() == IDOK) + TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(result.CheckTime); + } + +#if MPT_UPDATE_LEGACY + + if(!TrackerSettings::Instance().UpdateExperimentalNewAutoUpdate) + { + if(result.UpdateAvailable && (!autoUpdate || result.Version != TrackerSettings::Instance().UpdateIgnoreVersion)) { - CTrackApp::OpenURL(result.URL); + UpdateDialog dlg(result.Version, result.Date, result.URL); + if(dlg.DoModal() == IDOK) + { + CTrackApp::OpenURL(result.URL); + } + } else if(!result.UpdateAvailable && !autoUpdate) + { + Reporting::Information(U_("You already have the latest version of OpenMPT installed."), U_("OpenMPT Internet Update")); } - } else if(!result.UpdateAvailable && !autoUpdate) + return; + } + +#endif // MPT_UPDATE_LEGACY + + Update::versions updateData = nlohmann::json::parse(mpt::buffer_cast<std::string>(result.json)).get<Update::versions>(); + UpdateInfo updateInfo = GetBestDownload(updateData); + + if(!updateInfo.IsAvailable()) { - Reporting::Information(U_("You already have the latest version of OpenMPT installed."), U_("OpenMPT Internet Update")); + if(!autoUpdate) + { + Reporting::Information(U_("You already have the latest version of OpenMPT installed."), U_("OpenMPT Update")); + } + return; } + + auto & versionInfo = updateData[updateInfo.version]; + if(autoUpdate && (mpt::ToCString(versionInfo.version) == TrackerSettings::Instance().UpdateIgnoreVersion)) + { + return; + } + + if(autoUpdate && TrackerSettings::Instance().UpdateInstallAutomatically && !updateInfo.download.empty() && versionInfo.downloads[updateInfo.download].can_autoupdate && (Version::Current() >= Version::Parse(versionInfo.downloads[updateInfo.download].autoupdate_minversion))) + { + + CDoUpdate updateDlg(versionInfo.downloads[updateInfo.download], theApp.GetMainWnd()); + if(updateDlg.DoModal() != IDOK) + { + return; + } + + } else + { + + UpdateDialog dlg( + mpt::ToCString(versionInfo.version), + mpt::ToCString(versionInfo.date), + mpt::ToCString(versionInfo.changelog_url), + (!updateInfo.download.empty() && versionInfo.downloads[updateInfo.download].can_autoupdate && (Version::Current() >= Version::Parse(versionInfo.downloads[updateInfo.download].autoupdate_minversion))) ? _T("&Install now...") : + (!updateInfo.download.empty()) ? _T("&Download now...") : + _T("&View Announcement...") + ); + if(dlg.DoModal() != IDOK) + { + return; + } + + if(!updateInfo.download.empty() && versionInfo.downloads[updateInfo.download].can_autoupdate && (Version::Current() >= Version::Parse(versionInfo.downloads[updateInfo.download].autoupdate_minversion))) + { + CDoUpdate updateDlg(versionInfo.downloads[updateInfo.download], theApp.GetMainWnd()); + if(updateDlg.DoModal() != IDOK) + { + return; + } + } else if(!updateInfo.download.empty()) + { + CTrackApp::OpenURL(updateInfo.download); + } else + { + CTrackApp::OpenURL(versionInfo.announcement_url); + } + + } + } +mpt::ustring CUpdateCheck::GetFailureMessage(WPARAM wparam, LPARAM lparam) +{ + MPT_UNREFERENCED_PARAMETER(wparam); + const CUpdateCheck::Error &error = *reinterpret_cast<CUpdateCheck::Error*>(lparam); + return mpt::get_exception_text<mpt::ustring>(error); +} + + + void CUpdateCheck::ShowFailureGUI(WPARAM wparam, LPARAM lparam) { const CUpdateCheck::Error &error = *reinterpret_cast<CUpdateCheck::Error*>(lparam); @@ -512,7 +1546,7 @@ bool autoUpdate = wparam != 0; if(!autoUpdate) { - Reporting::Error(mpt::get_exception_text<mpt::ustring>(error), U_("OpenMPT Internet Update Error")); + Reporting::Error(mpt::get_exception_text<mpt::ustring>(error), U_("OpenMPT Update Error")); } } @@ -538,6 +1572,13 @@ } + +CUpdateCheck::Cancel::Cancel() +{ + return; +} + + ///////////////////////////////////////////////////////////// // CUpdateSetupDlg @@ -548,6 +1589,7 @@ ON_COMMAND(IDC_RADIO3, &CUpdateSetupDlg::OnSettingsChanged) ON_COMMAND(IDC_BUTTON1, &CUpdateSetupDlg::OnCheckNow) ON_CBN_SELCHANGE(IDC_COMBO_UPDATEFREQUENCY, &CUpdateSetupDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK_UPDATEINSTALLAUTOMATICALLY, &CUpdateSetupDlg::OnSettingsChanged) ON_COMMAND(IDC_CHECK1, &CUpdateSetupDlg::OnSettingsChanged) ON_NOTIFY(NM_CLICK, IDC_SYSLINK1, &CUpdateSetupDlg::OnShowStatisticsData) END_MESSAGE_MAP() @@ -575,7 +1617,7 @@ CheckDlgButton(IDC_CHECK_UPDATEENABLED, TrackerSettings::Instance().UpdateEnabled ? BST_CHECKED : BST_UNCHECKED); int radioID = 0; - int updateChannel = TrackerSettings::Instance().UpdateChannel; + uint32 updateChannel = TrackerSettings::Instance().UpdateChannel; if(updateChannel == UpdateChannelRelease) { radioID = IDC_RADIO1; @@ -629,6 +1671,8 @@ m_CbnUpdateFrequency.SetCurSel(ndx); } + CheckDlgButton(IDC_CHECK_UPDATEINSTALLAUTOMATICALLY, TrackerSettings::Instance().UpdateInstallAutomatically ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().UpdateStatistics ? BST_CHECKED : BST_UNCHECKED); GetDlgItem(IDC_STATIC_UPDATEPRIVACYTEXT)->SetWindowText(mpt::ToCString(CUpdateCheck::GetStatisticsUserInformation(true))); @@ -646,7 +1690,7 @@ { CUpdateCheck::Settings settings; - int updateChannel = TrackerSettings::Instance().UpdateChannel; + uint32 updateChannel = TrackerSettings::Instance().UpdateChannel; if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; @@ -654,14 +1698,43 @@ int updateCheckPeriod = (m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel()) == ~(DWORD_PTR)0) ? -1 : static_cast<int>(m_CbnUpdateFrequency.GetItemData(m_CbnUpdateFrequency.GetCurSel())); settings.periodDays = updateCheckPeriod; - settings.channel = updateChannel; + settings.channel = static_cast<UpdateChannel>(updateChannel); settings.sendStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); mpt::ustring statistics; - statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); + + statistics += U_("Update:") + UL_("\n"); statistics += UL_("\n"); + +#if MPT_UPDATE_LEGACY + if(settings.modeLegacy) + { + statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); + statistics += UL_("\n"); + } else +#endif // MPT_UPDATE_LEGACY + { + statistics += U_("GET ") + settings.apiURL + MPT_UFORMAT("update/{}")(GetChannelName(static_cast<UpdateChannel>(settings.channel))) + UL_("\n"); + statistics += UL_("\n"); + std::vector<mpt::ustring> keyAnchors = TrackerSettings::Instance().UpdateSigningKeysRootAnchors; + for(const auto & keyAnchor : keyAnchors) + { + statistics += U_("GET ") + keyAnchor + U_("signingkeys.jwkset.json") + UL_("\n"); + statistics += UL_("\n"); + } + } + if(settings.sendStatistics) { + statistics += U_("Statistics:") + UL_("\n"); + statistics += UL_("\n"); +#if MPT_UPDATE_LEGACY + if(!settings.modeLegacy) +#endif // MPT_UPDATE_LEGACY + { + statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); + statistics += UL_("\n"); + } if(settings.statisticsUUID.IsValid()) { statistics += U_("PUT ") + settings.apiURL + MPT_UFORMAT("statistics/{}")(settings.statisticsUUID) + UL_("\n"); @@ -714,6 +1787,7 @@ GetDlgItem(IDC_COMBO_UPDATEFREQUENCY)->EnableWindow(status); GetDlgItem(IDC_BUTTON1)->EnableWindow(status); GetDlgItem(IDC_LASTUPDATE)->EnableWindow(status); + GetDlgItem(IDC_CHECK_UPDATEINSTALLAUTOMATICALLY)->EnableWindow(status); GetDlgItem(IDC_STATIC_UPDATEPRIVACY)->EnableWindow(status); GetDlgItem(IDC_CHECK1)->EnableWindow(status); @@ -731,7 +1805,7 @@ void CUpdateSetupDlg::OnOK() { - int updateChannel = TrackerSettings::Instance().UpdateChannel; + uint32 updateChannel = TrackerSettings::Instance().UpdateChannel; if(IsDlgButtonChecked(IDC_RADIO1)) updateChannel = UpdateChannelRelease; if(IsDlgButtonChecked(IDC_RADIO2)) updateChannel = UpdateChannelNext; if(IsDlgButtonChecked(IDC_RADIO3)) updateChannel = UpdateChannelDevelopment; @@ -741,6 +1815,7 @@ TrackerSettings::Instance().UpdateEnabled = (IsDlgButtonChecked(IDC_CHECK_UPDATEENABLED) != BST_UNCHECKED); TrackerSettings::Instance().UpdateIntervalDays = updateCheckPeriod; + TrackerSettings::Instance().UpdateInstallAutomatically = (IsDlgButtonChecked(IDC_CHECK_UPDATEINSTALLAUTOMATICALLY) != BST_UNCHECKED); TrackerSettings::Instance().UpdateChannel = updateChannel; TrackerSettings::Instance().UpdateStatistics = (IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED); @@ -757,7 +1832,7 @@ void CUpdateSetupDlg::OnCheckNow() { - CMainFrame::GetMainFrame()->PostMessage(WM_COMMAND, ID_INTERNETUPDATE); + CUpdateCheck::DoManualUpdateCheck(); } Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 13367) +++ mptrack/UpdateCheck.h (working copy) @@ -24,7 +24,11 @@ OPENMPT_NAMESPACE_BEGIN -enum UpdateChannel +namespace HTTP { +class InternetSession; +} + +enum UpdateChannel : uint32 { UpdateChannelRelease = 1, UpdateChannelNext = 2, @@ -42,14 +46,19 @@ static mpt::ustring GetStatisticsUserInformation(bool shortText); +#if MPT_UPDATE_LEGACY static mpt::ustring GetDefaultChannelReleaseURL(); static mpt::ustring GetDefaultChannelNextURL(); static mpt::ustring GetDefaultChannelDevelopmentURL(); +#endif // MPT_UPDATE_LEGACY + static std::vector<mpt::ustring> GetDefaultUpdateSigningKeysRootAnchors(); static mpt::ustring GetDefaultAPIURL(); int32 GetNumCurrentRunningInstances(); + static bool IsSuitableUpdateMoment(); + static void DoAutoUpdateCheck() { StartUpdateCheckAsync(true); } static void DoManualUpdateCheck() { StartUpdateCheckAsync(false); } @@ -58,10 +67,13 @@ struct Context { CWnd *window; + UINT msgStart; UINT msgProgress; UINT msgSuccess; UINT msgFailure; + UINT msgCanceled; bool autoUpdate; + bool loadPersisted; std::string statistics; }; @@ -68,10 +80,14 @@ struct Settings { int32 periodDays; - uint32 channel; + UpdateChannel channel; + mpt::PathString persistencePath; +#if MPT_UPDATE_LEGACY + bool modeLegacy; mpt::ustring channelReleaseURL; mpt::ustring channelNextURL; mpt::ustring channelDevelopmentURL; +#endif // MPT_UPDATE_LEGACY mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; @@ -88,21 +104,35 @@ static CString FormatErrorCode(CString errorMessage, DWORD errorCode); }; + class Cancel + : public std::exception + { + public: + Cancel(); + }; + struct Result { time_t CheckTime; + std::vector<std::byte> json; +#if MPT_UPDATE_LEGACY bool UpdateAvailable; CString Version; CString Date; CString URL; +#endif // MPT_UPDATE_LEGACY Result() : CheckTime(time_t()) +#if MPT_UPDATE_LEGACY , UpdateAvailable(false) +#endif // MPT_UPDATE_LEGACY { return; } }; + static bool IsAutoUpdateFromMessage(WPARAM wparam, LPARAM lparam); + static CUpdateCheck::Result ResultFromMessage(WPARAM wparam, LPARAM lparam); static CUpdateCheck::Error ErrorFromMessage(WPARAM wparam, LPARAM lparam); @@ -109,10 +139,14 @@ static void ShowSuccessGUI(WPARAM wparam, LPARAM lparam); static void ShowFailureGUI(WPARAM wparam, LPARAM lparam); + static mpt::ustring GetFailureMessage(WPARAM wparam, LPARAM lparam); + public: +#if MPT_UPDATE_LEGACY // v2 static mpt::ustring GetUpdateURLV2(const Settings &settings); +#endif // MPT_UPDATE_LEGACY // v3 static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 @@ -131,8 +165,17 @@ static void CheckForUpdate(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); - static CUpdateCheck::Result SearchUpdate(const CUpdateCheck::Settings &settings, const std::string &statistics); // may throw - + static CUpdateCheck::Result SearchUpdate(const CUpdateCheck::Context &context, const CUpdateCheck::Settings &settings, const std::string &statistics); // may throw + + static void CleanOldUpdates(const CUpdateCheck::Settings &settings, const CUpdateCheck::Context &context); + + static void SendStatistics(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings, const std::string &statistics); // may throw + +#if MPT_UPDATE_LEGACY + static CUpdateCheck::Result SearchUpdateLegacy(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings); // may throw +#endif // MPT_UPDATE_LEGACY + static CUpdateCheck::Result SearchUpdateModern(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings); // may throw + }; @@ -142,6 +185,9 @@ public: CUpdateSetupDlg(); +public: + void SettingChanged(const SettingPath &changedPath) override; + protected: void DoDataExchange(CDataExchange *pDX) override; BOOL OnInitDialog() override; @@ -148,8 +194,6 @@ void OnOK() override; BOOL OnSetActive() override; - void SettingChanged(const SettingPath &changedPath) override; - afx_msg void OnSettingsChanged(); afx_msg void OnCheckNow(); afx_msg void OnShowStatisticsData(NMHDR * /*pNMHDR*/, LRESULT * /*pResult*/); |
|
Implemented in r13368. |
|
Enabled by default in r13995. Forum thread at https://forum.openmpt.org/index.php?topic=6535.0. |
|
This patch removes the old update check method. Note that it also removes the old statistics collecting method which we might want to still defer until we have the same kind of analysis tool for the new statistics. update-remove-legacy-v1.patch (13,935 bytes)
Index: common/BuildSettings.h =================================================================== --- common/BuildSettings.h (revision 13995) +++ common/BuildSettings.h (working copy) @@ -194,8 +194,6 @@ #if defined(MODPLUG_TRACKER) -#define MPT_UPDATE_LEGACY 1 - // Enable built-in test suite. #if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) #define ENABLE_TESTS Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 13995) +++ mptrack/TrackerSettings.cpp (working copy) @@ -321,14 +321,7 @@ , UpdateUpdateCheckPeriod_DEPRECATED(conf, U_("Update"), U_("UpdateCheckPeriod"), 7) , UpdateIntervalDays(conf, U_("Update"), U_("UpdateCheckIntervalDays"), 7) , UpdateChannel(conf, U_("Update"), U_("Channel"), UpdateChannelRelease) -#if MPT_UPDATE_LEGACY - , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) - , UpdateChannelReleaseURL(conf, U_("Update"), U_("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) - , UpdateChannelNextURL(conf, U_("Update"), U_("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) - , UpdateChannelDevelopmentURL(conf, U_("Update"), U_("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) -#else // !MPT_UPDATE_LEGACY , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), U_("https://update.openmpt.org/check/$VERSION/$GUID")) -#endif // MPT_UPDATE_LEGACY , UpdateAPIURL(conf, U_("Update"), U_("APIURL"), CUpdateCheck::GetDefaultAPIURL()) , UpdateStatisticsConsentAsked(conf, U_("Update"), U_("StatistisConsentAsked"), false) , UpdateStatistics(conf, U_("Update"), U_("Statistis"), false) @@ -335,9 +328,6 @@ , UpdateSendGUID_DEPRECATED(conf, U_("Update"), U_("SendGUID"), false) , UpdateShowUpdateHint(conf, U_("Update"), U_("ShowUpdateHint"), true) , UpdateIgnoreVersion(conf, U_("Update"), U_("IgnoreVersion"), _T("")) -#if MPT_UPDATE_LEGACY - , UpdateLegacyMethod(conf, U_("Update"), U_("LegacyMethod"), false) -#endif // MPT_UPDATE_LEGACY , UpdateSkipSignatureVerificationUNSECURE(conf, U_("Update"), U_("SkipSignatureVerification"), false) , UpdateSigningKeysRootAnchors(conf, U_("Update"), U_("SigningKeysRootAnchors"), CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors()) // Wine suppport @@ -687,9 +677,6 @@ } else { UpdateChannel = UpdateChannelDevelopment; -#if MPT_UPDATE_LEGACY - UpdateChannelDevelopmentURL = url; -#endif // MPT_UPDATE_LEGACY } UpdateStatistics = UpdateSendGUID_DEPRECATED.Get(); conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 13995) +++ mptrack/TrackerSettings.h (working copy) @@ -859,11 +859,6 @@ Setting<int32> UpdateIntervalDays; Setting<uint32> UpdateChannel; Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; -#if MPT_UPDATE_LEGACY - Setting<mpt::ustring> UpdateChannelReleaseURL; - Setting<mpt::ustring> UpdateChannelNextURL; - Setting<mpt::ustring> UpdateChannelDevelopmentURL; -#endif // MPT_UPDATE_LEGACY Setting<mpt::ustring> UpdateAPIURL; Setting<bool> UpdateStatisticsConsentAsked; Setting<bool> UpdateStatistics; @@ -870,9 +865,6 @@ Setting<bool> UpdateSendGUID_DEPRECATED; Setting<bool> UpdateShowUpdateHint; Setting<CString> UpdateIgnoreVersion; -#if MPT_UPDATE_LEGACY - Setting<bool> UpdateLegacyMethod; -#endif // MPT_UPDATE_LEGACY Setting<bool> UpdateSkipSignatureVerificationUNSECURE; Setting<std::vector<mpt::ustring>> UpdateSigningKeysRootAnchors; Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 13995) +++ mptrack/UpdateCheck.cpp (working copy) @@ -393,26 +393,6 @@ } -#if MPT_UPDATE_LEGACY - -mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() -{ - return U_("https://update.openmpt.org/check/$VERSION/$GUID"); -} - -mpt::ustring CUpdateCheck::GetDefaultChannelNextURL() -{ - return U_("https://update.openmpt.org/check/next/$VERSION/$GUID"); -} - -mpt::ustring CUpdateCheck::GetDefaultChannelDevelopmentURL() -{ - return U_("https://update.openmpt.org/check/testing/$VERSION/$GUID"); -} - -#endif // MPT_UPDATE_LEGACY - - std::vector<mpt::ustring> CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors() { // IMPORTANT: @@ -474,15 +454,7 @@ const double secsSinceLastCheck = difftime(now, lastCheck); if(secsSinceLastCheck > 0.0 && secsSinceLastCheck < updateCheckPeriod * 86400.0) { -#if MPT_UPDATE_LEGACY - if(TrackerSettings::Instance().UpdateLegacyMethod) - { - return; - } else -#endif // MPT_UPDATE_LEGACY - { - loadPersisted = true; - } + loadPersisted = true; } // Never ran update checks before, so we notify the user of automatic update checks. @@ -555,12 +527,6 @@ : periodDays(TrackerSettings::Instance().UpdateIntervalDays) , channel(static_cast<UpdateChannel>(TrackerSettings::Instance().UpdateChannel.Get())) , persistencePath(theApp.GetConfigPath()) -#if MPT_UPDATE_LEGACY - , modeLegacy(TrackerSettings::Instance().UpdateLegacyMethod) - , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) - , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) - , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) -#endif // MPT_UPDATE_LEGACY , apiURL(TrackerSettings::Instance().UpdateAPIURL) , sendStatistics(TrackerSettings::Instance().UpdateStatistics) , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) @@ -653,55 +619,6 @@ } -#if MPT_UPDATE_LEGACY -mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) -{ - mpt::ustring updateURL; - if(settings.channel == UpdateChannelRelease) - { - updateURL = settings.channelReleaseURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelReleaseURL(); - } - } else if(settings.channel == UpdateChannelNext) - { - updateURL = settings.channelNextURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelNextURL(); - } - } else if(settings.channel == UpdateChannelDevelopment) - { - updateURL = settings.channelDevelopmentURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelDevelopmentURL(); - } - } else - { - updateURL = settings.channelReleaseURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelReleaseURL(); - } - } - if(updateURL.find(U_("://")) == mpt::ustring::npos) - { - updateURL = U_("https://") + updateURL; - } - // Build update URL - updateURL = mpt::String::Replace(updateURL, U_("$VERSION"), MPT_UFORMAT("{}-{}-{}") - ( Version::Current() - , BuildVariants().GuessCurrentBuildName() - , settings.sendStatistics ? mpt::OS::Windows::Version::Current().GetNameShort() : U_("unknown") - )); - updateURL = mpt::String::Replace(updateURL, U_("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : U_("anonymous")); - return updateURL; -} -#endif // MPT_UPDATE_LEGACY - - // Run update check (independent thread) CUpdateCheck::Result CUpdateCheck::SearchUpdate(const CUpdateCheck::Context &context, const CUpdateCheck::Settings &settings, const std::string &statistics) { @@ -719,13 +636,7 @@ { throw CUpdateCheck::Cancel(); } -#if MPT_UPDATE_LEGACY - if(settings.modeLegacy) { - result = SearchUpdateLegacy(internet, settings); - } else -#endif // MPT_UPDATE_LEGACY - { bool loaded = false; if(context.loadPersisted) { @@ -811,14 +722,6 @@ { if(settings.sendStatistics) { - if(!settings.modeLegacy) - { - HTTP::Request requestLegacyUpdate; - requestLegacyUpdate.SetURI(ParseURI(GetUpdateURLV2(settings))); - requestLegacyUpdate.method = HTTP::Method::Get; - requestLegacyUpdate.flags = HTTP::NoCache; - HTTP::Result resultLegacyUpdateHTTP = internet(requestLegacyUpdate); - } HTTP::Request requestStatistics; if(settings.statisticsUUID.IsValid()) { @@ -839,67 +742,6 @@ } -#if MPT_UPDATE_LEGACY -CUpdateCheck::Result CUpdateCheck::SearchUpdateLegacy(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings) -{ - - HTTP::Request request; - request.SetURI(ParseURI(GetUpdateURLV2(settings))); - request.method = HTTP::Method::Get; - request.flags = HTTP::NoCache; - - HTTP::Result resultHTTP = internet(request); - - // Retrieve HTTP status code. - if(resultHTTP.Status >= 400) - { - throw CUpdateCheck::Error(MPT_CFORMAT("Version information could not be found on the server (HTTP status code {}). Maybe your version of OpenMPT is too old!")(resultHTTP.Status)); - } - - // Now, evaluate the downloaded data. - CUpdateCheck::Result result; - result.UpdateAvailable = false; - result.CheckTime = time(nullptr); - CString resultData = mpt::ToCString(mpt::Charset::UTF8, mpt::buffer_cast<std::string>(resultHTTP.Data)); - if(resultData.CompareNoCase(_T("noupdate")) != 0) - { - CString token; - int parseStep = 0, parsePos = 0; - while(!(token = resultData.Tokenize(_T("\n"), parsePos)).IsEmpty()) - { - token.Trim(); - switch(parseStep++) - { - case 0: - if(token.CompareNoCase(_T("update")) != 0) - { - throw CUpdateCheck::Error(_T("Could not understand server response. Maybe your version of OpenMPT is too old!")); - } - break; - case 1: - result.Version = token; - break; - case 2: - result.Date = token; - break; - case 3: - result.URL = token; - break; - } - } - if(parseStep < 4) - { - throw CUpdateCheck::Error(_T("Could not understand server response. Maybe your version of OpenMPT is too old!")); - } - result.UpdateAvailable = true; - } - - return result; - -} -#endif // MPT_UPDATE_LEGACY - - CUpdateCheck::Result CUpdateCheck::SearchUpdateModern(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings) { @@ -1450,26 +1292,6 @@ TrackerSettings::Instance().UpdateLastUpdateCheck = mpt::Date::Unix(result.CheckTime); } -#if MPT_UPDATE_LEGACY - - if(TrackerSettings::Instance().UpdateLegacyMethod) - { - if(result.UpdateAvailable && (!autoUpdate || result.Version != TrackerSettings::Instance().UpdateIgnoreVersion)) - { - UpdateDialog dlg(result.Version, result.Date, result.URL); - if(dlg.DoModal() == IDOK) - { - CTrackApp::OpenURL(result.URL); - } - } else if(!result.UpdateAvailable && !autoUpdate) - { - Reporting::Information(U_("You already have the latest version of OpenMPT installed."), U_("OpenMPT Internet Update")); - } - return; - } - -#endif // MPT_UPDATE_LEGACY - Update::versions updateData = nlohmann::json::parse(mpt::buffer_cast<std::string>(result.json)).get<Update::versions>(); UpdateInfo updateInfo = GetBestDownload(updateData); @@ -1708,14 +1530,7 @@ statistics += U_("Update:") + UL_("\n"); statistics += UL_("\n"); -#if MPT_UPDATE_LEGACY - if(settings.modeLegacy) { - statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); - statistics += UL_("\n"); - } else -#endif // MPT_UPDATE_LEGACY - { statistics += U_("GET ") + settings.apiURL + MPT_UFORMAT("update/{}")(GetChannelName(static_cast<UpdateChannel>(settings.channel))) + UL_("\n"); statistics += UL_("\n"); std::vector<mpt::ustring> keyAnchors = TrackerSettings::Instance().UpdateSigningKeysRootAnchors; @@ -1730,13 +1545,6 @@ { statistics += U_("Statistics:") + UL_("\n"); statistics += UL_("\n"); -#if MPT_UPDATE_LEGACY - if(!settings.modeLegacy) -#endif // MPT_UPDATE_LEGACY - { - statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); - statistics += UL_("\n"); - } if(settings.statisticsUUID.IsValid()) { statistics += U_("PUT ") + settings.apiURL + MPT_UFORMAT("statistics/{}")(settings.statisticsUUID) + UL_("\n"); Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 13995) +++ mptrack/UpdateCheck.h (working copy) @@ -46,12 +46,6 @@ static mpt::ustring GetStatisticsUserInformation(bool shortText); -#if MPT_UPDATE_LEGACY - static mpt::ustring GetDefaultChannelReleaseURL(); - static mpt::ustring GetDefaultChannelNextURL(); - static mpt::ustring GetDefaultChannelDevelopmentURL(); -#endif // MPT_UPDATE_LEGACY - static std::vector<mpt::ustring> GetDefaultUpdateSigningKeysRootAnchors(); static mpt::ustring GetDefaultAPIURL(); @@ -82,12 +76,6 @@ int32 periodDays; UpdateChannel channel; mpt::PathString persistencePath; -#if MPT_UPDATE_LEGACY - bool modeLegacy; - mpt::ustring channelReleaseURL; - mpt::ustring channelNextURL; - mpt::ustring channelDevelopmentURL; -#endif // MPT_UPDATE_LEGACY mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; @@ -115,17 +103,8 @@ { time_t CheckTime; std::vector<std::byte> json; -#if MPT_UPDATE_LEGACY - bool UpdateAvailable; - CString Version; - CString Date; - CString URL; -#endif // MPT_UPDATE_LEGACY Result() : CheckTime(time_t()) -#if MPT_UPDATE_LEGACY - , UpdateAvailable(false) -#endif // MPT_UPDATE_LEGACY { return; } @@ -143,11 +122,6 @@ public: -#if MPT_UPDATE_LEGACY - // v2 - static mpt::ustring GetUpdateURLV2(const Settings &settings); -#endif // MPT_UPDATE_LEGACY - // v3 static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 @@ -171,9 +145,6 @@ static void SendStatistics(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings, const std::string &statistics); // may throw -#if MPT_UPDATE_LEGACY - static CUpdateCheck::Result SearchUpdateLegacy(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings); // may throw -#endif // MPT_UPDATE_LEGACY static CUpdateCheck::Result SearchUpdateModern(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings); // may throw }; |
|
update-remove-legacy-v3.patch (15,666 bytes)
Index: common/BuildSettings.h =================================================================== --- common/BuildSettings.h (revision 15722) +++ common/BuildSettings.h (working copy) @@ -209,8 +209,6 @@ #if defined(MODPLUG_TRACKER) -#define MPT_UPDATE_LEGACY 1 - // Enable built-in test suite. #if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) #define ENABLE_TESTS Index: mptrack/TrackerSettings.cpp =================================================================== --- mptrack/TrackerSettings.cpp (revision 15722) +++ mptrack/TrackerSettings.cpp (working copy) @@ -326,14 +326,7 @@ , UpdateUpdateCheckPeriod_DEPRECATED(conf, U_("Update"), U_("UpdateCheckPeriod"), 7) , UpdateIntervalDays(conf, U_("Update"), U_("UpdateCheckIntervalDays"), 7) , UpdateChannel(conf, U_("Update"), U_("Channel"), UpdateChannelRelease) -#if MPT_UPDATE_LEGACY - , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) - , UpdateChannelReleaseURL(conf, U_("Update"), U_("ChannelReleaseURL"), CUpdateCheck::GetDefaultChannelReleaseURL()) - , UpdateChannelNextURL(conf, U_("Update"), U_("ChannelStableURL"), CUpdateCheck::GetDefaultChannelNextURL()) - , UpdateChannelDevelopmentURL(conf, U_("Update"), U_("ChannelDevelopmentURL"), CUpdateCheck::GetDefaultChannelDevelopmentURL()) -#else // !MPT_UPDATE_LEGACY , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), U_("https://update.openmpt.org/check/$VERSION/$GUID")) -#endif // MPT_UPDATE_LEGACY , UpdateAPIURL(conf, U_("Update"), U_("APIURL"), CUpdateCheck::GetDefaultAPIURL()) , UpdateStatisticsConsentAsked(conf, U_("Update"), U_("StatistisConsentAsked"), false) , UpdateStatistics(conf, U_("Update"), U_("Statistis"), false) @@ -340,9 +333,6 @@ , UpdateSendGUID_DEPRECATED(conf, U_("Update"), U_("SendGUID"), false) , UpdateShowUpdateHint(conf, U_("Update"), U_("ShowUpdateHint"), true) , UpdateIgnoreVersion(conf, U_("Update"), U_("IgnoreVersion"), _T("")) -#if MPT_UPDATE_LEGACY - , UpdateLegacyMethod(conf, U_("Update"), U_("LegacyMethod"), false) -#endif // MPT_UPDATE_LEGACY , UpdateSkipSignatureVerificationUNSECURE(conf, U_("Update"), U_("SkipSignatureVerification"), false) , UpdateSigningKeysRootAnchors(conf, U_("Update"), U_("SigningKeysRootAnchors"), CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors()) #endif // MPT_ENABLE_UPDATE @@ -822,9 +812,6 @@ } else { UpdateChannel = UpdateChannelDevelopment; -#if MPT_UPDATE_LEGACY - UpdateChannelDevelopmentURL = url; -#endif // MPT_UPDATE_LEGACY } UpdateStatistics = UpdateSendGUID_DEPRECATED.Get(); conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath()); Index: mptrack/TrackerSettings.h =================================================================== --- mptrack/TrackerSettings.h (revision 15722) +++ mptrack/TrackerSettings.h (working copy) @@ -901,11 +901,6 @@ Setting<int32> UpdateIntervalDays; Setting<uint32> UpdateChannel; Setting<mpt::ustring> UpdateUpdateURL_DEPRECATED; -#if MPT_UPDATE_LEGACY - Setting<mpt::ustring> UpdateChannelReleaseURL; - Setting<mpt::ustring> UpdateChannelNextURL; - Setting<mpt::ustring> UpdateChannelDevelopmentURL; -#endif // MPT_UPDATE_LEGACY Setting<mpt::ustring> UpdateAPIURL; Setting<bool> UpdateStatisticsConsentAsked; Setting<bool> UpdateStatistics; @@ -912,9 +907,6 @@ Setting<bool> UpdateSendGUID_DEPRECATED; Setting<bool> UpdateShowUpdateHint; Setting<CString> UpdateIgnoreVersion; -#if MPT_UPDATE_LEGACY - Setting<bool> UpdateLegacyMethod; -#endif // MPT_UPDATE_LEGACY Setting<bool> UpdateSkipSignatureVerificationUNSECURE; Setting<std::vector<mpt::ustring>> UpdateSigningKeysRootAnchors; Index: mptrack/UpdateCheck.cpp =================================================================== --- mptrack/UpdateCheck.cpp (revision 15722) +++ mptrack/UpdateCheck.cpp (working copy) @@ -399,26 +399,6 @@ } -#if MPT_UPDATE_LEGACY - -mpt::ustring CUpdateCheck::GetDefaultChannelReleaseURL() -{ - return U_("https://update.openmpt.org/check/$VERSION/$GUID"); -} - -mpt::ustring CUpdateCheck::GetDefaultChannelNextURL() -{ - return U_("https://update.openmpt.org/check/next/$VERSION/$GUID"); -} - -mpt::ustring CUpdateCheck::GetDefaultChannelDevelopmentURL() -{ - return U_("https://update.openmpt.org/check/testing/$VERSION/$GUID"); -} - -#endif // MPT_UPDATE_LEGACY - - std::vector<mpt::ustring> CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors() { // IMPORTANT: @@ -480,15 +460,7 @@ const double secsSinceLastCheck = difftime(now, lastCheck); if(secsSinceLastCheck > 0.0 && secsSinceLastCheck < updateCheckPeriod * 86400.0) { -#if MPT_UPDATE_LEGACY - if(TrackerSettings::Instance().UpdateLegacyMethod) - { - return; - } else -#endif // MPT_UPDATE_LEGACY - { - loadPersisted = true; - } + loadPersisted = true; } // Never ran update checks before, so we notify the user of automatic update checks. @@ -561,12 +533,6 @@ : periodDays(TrackerSettings::Instance().UpdateIntervalDays) , channel(static_cast<UpdateChannel>(TrackerSettings::Instance().UpdateChannel.Get())) , persistencePath(theApp.GetConfigPath()) -#if MPT_UPDATE_LEGACY - , modeLegacy(TrackerSettings::Instance().UpdateLegacyMethod) - , channelReleaseURL(TrackerSettings::Instance().UpdateChannelReleaseURL) - , channelNextURL(TrackerSettings::Instance().UpdateChannelNextURL) - , channelDevelopmentURL(TrackerSettings::Instance().UpdateChannelDevelopmentURL) -#endif // MPT_UPDATE_LEGACY , apiURL(TrackerSettings::Instance().UpdateAPIURL) , sendStatistics(TrackerSettings::Instance().UpdateStatistics) , statisticsUUID(TrackerSettings::Instance().VersionInstallGUID) @@ -661,62 +627,10 @@ } -#if MPT_UPDATE_LEGACY -mpt::ustring CUpdateCheck::GetUpdateURLV2(const CUpdateCheck::Settings &settings) -{ - mpt::ustring updateURL; - if(settings.channel == UpdateChannelRelease) - { - updateURL = settings.channelReleaseURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelReleaseURL(); - } - } else if(settings.channel == UpdateChannelNext) - { - updateURL = settings.channelNextURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelNextURL(); - } - } else if(settings.channel == UpdateChannelDevelopment) - { - updateURL = settings.channelDevelopmentURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelDevelopmentURL(); - } - } else - { - updateURL = settings.channelReleaseURL; - if(updateURL.empty()) - { - updateURL = GetDefaultChannelReleaseURL(); - } - } - if(updateURL.find(U_("://")) == mpt::ustring::npos) - { - updateURL = U_("https://") + updateURL; - } - // Build update URL - updateURL = mpt::String::Replace(updateURL, U_("$VERSION"), MPT_UFORMAT("{}-{}-{}") - ( Version::Current() - , BuildVariants().GuessCurrentBuildName() - , settings.sendStatistics ? mpt::OS::Windows::Version::Current().GetNameShort() : U_("unknown") - )); - updateURL = mpt::String::Replace(updateURL, U_("$GUID"), settings.sendStatistics ? mpt::ufmt::val(settings.statisticsUUID) : U_("anonymous")); - return updateURL; -} -#endif // MPT_UPDATE_LEGACY - - // Run update check (independent thread) UpdateCheckResult CUpdateCheck::SearchUpdate(const CUpdateCheck::Context &context, const CUpdateCheck::Settings &settings, const std::string &statistics) { UpdateCheckResult result; - -#if MPT_UPDATE_LEGACY - if(settings.modeLegacy) { if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 0)) { @@ -726,43 +640,6 @@ { throw CUpdateCheck::Cancel(); } - { - HTTP::InternetSession internet(Version::Current().GetOpenMPTVersionString()); - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 30)) - { - throw CUpdateCheck::Cancel(); - } - result = SearchUpdateLegacy(internet, settings); - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 50)) - { - throw CUpdateCheck::Cancel(); - } - SendStatistics(internet, settings, statistics); - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 70)) - { - throw CUpdateCheck::Cancel(); - } - } - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 90)) - { - throw CUpdateCheck::Cancel(); - } - CleanOldUpdates(settings, context); - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 100)) - { - throw CUpdateCheck::Cancel(); - } - } else -#endif // MPT_UPDATE_LEGACY - { - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 0)) - { - throw CUpdateCheck::Cancel(); - } - if(!context.window->SendMessage(context.msgProgress, context.autoUpdate ? 1 : 0, 10)) - { - throw CUpdateCheck::Cancel(); - } bool loaded = false; // try to load cached results before establishing any connection if(context.loadPersisted) @@ -860,17 +737,6 @@ { if(settings.sendStatistics) { - if(!settings.modeLegacy) - { - HTTP::Request requestLegacyUpdate; - requestLegacyUpdate.SetURI(ParseURI(GetUpdateURLV2(settings))); - requestLegacyUpdate.method = HTTP::Method::Get; - requestLegacyUpdate.flags = HTTP::NoCache; -#if defined(MPT_BUILD_RETRO) - requestLegacyUpdate.InsecureTLSDowngradeWindowsXP(); -#endif // MPT_BUILD_RETRO - HTTP::Result resultLegacyUpdateHTTP = internet(requestLegacyUpdate); - } HTTP::Request requestStatistics; if(settings.statisticsUUID.IsValid()) { @@ -894,70 +760,6 @@ } -#if MPT_UPDATE_LEGACY -UpdateCheckResult CUpdateCheck::SearchUpdateLegacy(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings) -{ - - HTTP::Request request; - request.SetURI(ParseURI(GetUpdateURLV2(settings))); - request.method = HTTP::Method::Get; - request.flags = HTTP::NoCache; - -#if defined(MPT_BUILD_RETRO) - request.InsecureTLSDowngradeWindowsXP(); -#endif // MPT_BUILD_RETRO - HTTP::Result resultHTTP = internet(request); - - // Retrieve HTTP status code. - if(resultHTTP.Status >= 400) - { - throw CUpdateCheck::Error(MPT_CFORMAT("Version information could not be found on the server (HTTP status code {}). Maybe your version of OpenMPT is too old!")(resultHTTP.Status)); - } - - // Now, evaluate the downloaded data. - UpdateCheckResult result; - result.UpdateAvailable = false; - result.CheckTime = time(nullptr); - CString resultData = mpt::ToCString(mpt::Charset::UTF8, mpt::buffer_cast<std::string>(resultHTTP.Data)); - if(resultData.CompareNoCase(_T("noupdate")) != 0) - { - CString token; - int parseStep = 0, parsePos = 0; - while(!(token = resultData.Tokenize(_T("\n"), parsePos)).IsEmpty()) - { - token.Trim(); - switch(parseStep++) - { - case 0: - if(token.CompareNoCase(_T("update")) != 0) - { - throw CUpdateCheck::Error(_T("Could not understand server response. Maybe your version of OpenMPT is too old!")); - } - break; - case 1: - result.Version = token; - break; - case 2: - result.Date = token; - break; - case 3: - result.URL = token; - break; - } - } - if(parseStep < 4) - { - throw CUpdateCheck::Error(_T("Could not understand server response. Maybe your version of OpenMPT is too old!")); - } - result.UpdateAvailable = true; - } - - return result; - -} -#endif // MPT_UPDATE_LEGACY - - UpdateCheckResult CUpdateCheck::SearchUpdateModern(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings) { @@ -1523,41 +1325,6 @@ { bool modal = !autoUpdate; -#if MPT_UPDATE_LEGACY - - if(TrackerSettings::Instance().UpdateLegacyMethod) - { - if(!result.UpdateAvailable) - { - if(modal) - { - Reporting::Information(U_("You already have the latest version of OpenMPT installed."), U_("OpenMPT Update")); - } - return; - } - - // always show indicator, do not highlight it with a tooltip if we show a modal window later - if(!CMainFrame::GetMainFrame()->ShowUpdateIndicator(result, result.Version, result.URL, !modal)) - { - // on failure to show indicator, continue and show modal dialog - modal = true; - } - - if(!modal) - { - return; - } - UpdateDialog dlg(result.Version, result.Date, result.URL); - if(dlg.DoModal() != IDOK) - { - return; - } - CTrackApp::OpenURL(result.URL); - return; - } - -#endif // MPT_UPDATE_LEGACY - Update::versions updateData = nlohmann::json::parse(mpt::buffer_cast<std::string>(result.json)).get<Update::versions>(); UpdateInfo updateInfo = GetBestDownload(updateData); @@ -1808,14 +1575,7 @@ statistics += U_("Update:") + UL_("\n"); statistics += UL_("\n"); -#if MPT_UPDATE_LEGACY - if(settings.modeLegacy) { - statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); - statistics += UL_("\n"); - } else -#endif // MPT_UPDATE_LEGACY - { statistics += U_("GET ") + settings.apiURL + MPT_UFORMAT("update/{}")(GetChannelName(static_cast<UpdateChannel>(settings.channel))) + UL_("\n"); statistics += UL_("\n"); std::vector<mpt::ustring> keyAnchors = TrackerSettings::Instance().UpdateSigningKeysRootAnchors; @@ -1830,13 +1590,6 @@ { statistics += U_("Statistics:") + UL_("\n"); statistics += UL_("\n"); -#if MPT_UPDATE_LEGACY - if(!settings.modeLegacy) -#endif // MPT_UPDATE_LEGACY - { - statistics += U_("GET ") + CUpdateCheck::GetUpdateURLV2(settings) + UL_("\n"); - statistics += UL_("\n"); - } if(settings.statisticsUUID.IsValid()) { statistics += U_("PUT ") + settings.apiURL + MPT_UFORMAT("statistics/{}")(settings.statisticsUUID) + UL_("\n"); Index: mptrack/UpdateCheck.h =================================================================== --- mptrack/UpdateCheck.h (revision 15722) +++ mptrack/UpdateCheck.h (working copy) @@ -42,14 +42,10 @@ { time_t CheckTime = time_t{}; std::vector<std::byte> json; -#if MPT_UPDATE_LEGACY - bool UpdateAvailable = false; - CString Version; - CString Date; - CString URL; -#endif // MPT_UPDATE_LEGACY - - bool IsFromCache() const noexcept { return CheckTime == time_t{}; } + bool IsFromCache() const noexcept + { + return CheckTime == time_t{}; + } }; class CUpdateCheck @@ -63,12 +59,6 @@ static mpt::ustring GetStatisticsUserInformation(bool shortText); -#if MPT_UPDATE_LEGACY - static mpt::ustring GetDefaultChannelReleaseURL(); - static mpt::ustring GetDefaultChannelNextURL(); - static mpt::ustring GetDefaultChannelDevelopmentURL(); -#endif // MPT_UPDATE_LEGACY - static std::vector<mpt::ustring> GetDefaultUpdateSigningKeysRootAnchors(); static mpt::ustring GetDefaultAPIURL(); @@ -99,12 +89,6 @@ int32 periodDays; UpdateChannel channel; mpt::PathString persistencePath; -#if MPT_UPDATE_LEGACY - bool modeLegacy; - mpt::ustring channelReleaseURL; - mpt::ustring channelNextURL; - mpt::ustring channelDevelopmentURL; -#endif // MPT_UPDATE_LEGACY mpt::ustring apiURL; bool sendStatistics; mpt::UUID statisticsUUID; @@ -143,11 +127,6 @@ public: -#if MPT_UPDATE_LEGACY - // v2 - static mpt::ustring GetUpdateURLV2(const Settings &settings); -#endif // MPT_UPDATE_LEGACY - // v3 static std::string GetStatisticsDataV3(const Settings &settings); // UTF8 @@ -171,9 +150,6 @@ static void SendStatistics(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings, const std::string &statistics); // may throw -#if MPT_UPDATE_LEGACY - static UpdateCheckResult SearchUpdateLegacy(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings); // may throw -#endif // MPT_UPDATE_LEGACY static UpdateCheckResult SearchUpdateModern(HTTP::InternetSession &internet, const CUpdateCheck::Settings &settings); // may throw }; |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2017-08-14 10:24 | Saga Musix | New Issue | |
2017-08-14 10:25 | Saga Musix | Description Updated | |
2017-08-14 11:27 | manx | Note Added: 0003167 | |
2017-08-14 11:32 | Saga Musix | Description Updated | |
2017-08-14 12:40 | Saga Musix | Description Updated | |
2017-08-14 12:42 | Saga Musix | Description Updated | |
2017-08-16 22:51 | Saga Musix | Description Updated | |
2017-09-22 15:10 | manx | Note Added: 0003230 | |
2017-09-22 15:28 | Saga Musix | Note Added: 0003232 | |
2017-09-22 15:38 | manx | Note Added: 0003233 | |
2018-05-27 06:22 | manx | Relationship added | related to 0001123 |
2018-08-22 10:55 | manx | File Added: Screenshot at 2018-01-15 11:58:45.png | |
2018-08-22 10:55 | manx | Note Added: 0003605 | |
2018-08-22 16:03 | manx | File Added: updatedialog-v2.png | |
2018-08-22 16:05 | manx | File Added: update-statistics-v2.patch | |
2018-09-12 06:12 | manx | Relationship added | related to 0000649 |
2018-09-12 13:46 | manx | File Added: update-statistics-v3.patch | |
2018-11-04 15:39 | manx | File Added: update-statistics-v5.patch | |
2018-11-09 09:12 | manx | File Added: update-statistics-v7.patch | |
2018-11-09 09:12 | manx | Note Added: 0003708 | |
2018-11-11 15:49 | manx | Note Added: 0003712 | |
2019-01-03 12:46 | manx | Relationship added | related to 0001185 |
2019-01-07 15:14 | manx | Relationship added | related to 0001186 |
2019-03-08 12:55 | manx | Relationship added | related to 0001213 |
2019-03-08 15:34 | manx | Relationship added | related to 0001214 |
2020-05-10 09:06 | manx | Target Version | OpenMPT 1.?? (long term goals) => OpenMPT 1.30.01.00 / libopenmpt 0.6.0 (upgrade first) |
2020-06-07 07:32 | manx | Note Added: 0004373 | |
2020-06-07 07:35 | manx | Assigned To | => manx |
2020-06-07 07:35 | manx | Status | new => confirmed |
2020-06-07 07:36 | manx | Status | confirmed => assigned |
2020-07-27 07:59 | manx | Note Added: 0004408 | |
2020-07-27 07:59 | manx | File Added: autoupdate-v10.patch | |
2020-07-27 08:03 | manx | Note Added: 0004409 | |
2020-07-27 08:03 | manx | Status | assigned => feedback |
2020-10-08 09:35 | manx | Relationship added | related to 0001377 |
2020-12-29 14:29 | manx | Note Added: 0004582 | |
2020-12-29 14:39 | manx | Note Added: 0004583 | |
2020-12-29 14:39 | manx | File Added: update-remove-legacy-v1.patch | |
2021-01-10 18:28 | manx | Status | feedback => resolved |
2021-01-10 18:28 | manx | Resolution | open => fixed |
2021-01-10 18:28 | manx | Fixed in Version | => OpenMPT 1.30.01.00 / libopenmpt 0.6.0 (upgrade first) |
2021-03-01 15:32 | manx | Relationship added | related to 0001428 |
2021-06-01 10:59 | manx | Relationship added | related to 0001466 |
2021-09-24 13:38 | manx | Note Added: 0004881 | |
2021-09-24 13:38 | manx | File Added: update-remove-legacy-v3.patch | |
2021-12-25 18:20 | manx | Relationship added | related to 0001532 |
2024-10-10 08:16 | manx | Category | General => Installer and Update |