mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-04 02:00:43 +00:00
305 lines
11 KiB
C++
305 lines
11 KiB
C++
/* CheckUpdates
|
|
*
|
|
* Copyright (c) 2011-2018 Mark Watkins
|
|
* Copyright (c) 2020-2024 OSCAR Team
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file COPYING in the main directory of the source code
|
|
* for more details. */
|
|
|
|
#include <QNetworkRequest>
|
|
#include <QNetworkReply>
|
|
#include <QMessageBox>
|
|
#include <QDesktopServices>
|
|
#include <QResource>
|
|
#include <QTimer>
|
|
#include <QFile>
|
|
#include <QDir>
|
|
#include <QDate>
|
|
#include <QDebug>
|
|
#include <QXmlStreamReader>
|
|
#include <QDesktopWidget>
|
|
#include <QProcess>
|
|
|
|
#include "checkupdates.h"
|
|
#include "version.h"
|
|
#include "mainwindow.h"
|
|
|
|
extern MainWindow *mainwin;
|
|
|
|
struct VersionInfo {
|
|
QString group; // test or release
|
|
QString platform; // All or Requested platform
|
|
QString version; // version number
|
|
QString urlInstaller; // URL for installer page
|
|
QString notes; // any notes
|
|
};
|
|
|
|
CheckUpdates::CheckUpdates(QWidget *parent) :
|
|
QMainWindow(parent)
|
|
{
|
|
manager = new QNetworkAccessManager(this);
|
|
}
|
|
|
|
CheckUpdates::~CheckUpdates()
|
|
{
|
|
disconnect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
|
|
}
|
|
|
|
QString platformStr()
|
|
{
|
|
static QString platform;
|
|
|
|
#if defined(Q_OS_WIN64)
|
|
platform="win64";
|
|
#elif defined(Q_OS_WIN)
|
|
platform="win32";
|
|
#elif defined(Q_OS_MACOS)
|
|
platform="macOS";
|
|
#elif defined(Q_OS_LINUX)
|
|
platform="linux";
|
|
#else
|
|
platform="unknown";
|
|
#endif
|
|
return platform;
|
|
}
|
|
|
|
static const QString OSCAR_Version_File = "http://apneaboard.net/OSCAR/versions.xml";
|
|
|
|
static QString versionXML;
|
|
|
|
/*! \fn readLocalVersions
|
|
\brief Reads versions.xml from local OSCAR Data directory
|
|
*/
|
|
QString readLocalVersions() {
|
|
// Connect and read XML file from disk
|
|
QString filename = GetAppData() + "/versions.xml";
|
|
qDebug() << "Local version control file at" << filename;
|
|
QFile file(filename);
|
|
if(!file.open(QFile::ReadOnly | QFile::Text)) {
|
|
qDebug() << "Cannot open local version control file" << filename << "-" << file.errorString() << "version check disabled";
|
|
return QString();
|
|
}
|
|
QByteArray qba = file.readAll();
|
|
QFileDevice::FileError error = file.error();
|
|
file.close();
|
|
if (error != QFile::NoError) {
|
|
qDebug() << "Error reading local version control file" << filename << "-" << file.errorString() << "version check disabled";
|
|
qDebug() << "versionXML" << versionXML;
|
|
return QString();
|
|
}
|
|
return QString(qba).toLower();
|
|
}
|
|
|
|
/*! \fn GetVersionInfo
|
|
\brief Extracts newer version info for this platform
|
|
If returned versionInfo.version is empty, no newer version was found
|
|
*/
|
|
VersionInfo getVersionInfo (QString type, QString platform) {
|
|
VersionInfo foundInfo;
|
|
|
|
QXmlStreamReader reader(versionXML);
|
|
|
|
if (reader.readNextStartElement()) {
|
|
if (reader.name() == "oscar"){
|
|
//qDebug() << "expecting oscar, read" << reader.name();
|
|
while(reader.readNextStartElement()){
|
|
//qDebug() << "expecting group, read" << reader.name() << "with id" << reader.attributes().value("id").toString();
|
|
if(reader.name() == "group" &&
|
|
reader.attributes().hasAttribute("id")){
|
|
if (reader.attributes().value("id").toString() == type) {
|
|
while(reader.readNextStartElement()) {
|
|
//qDebug() << "expecting url or platform, read" << reader.name();
|
|
if (reader.name() == "installers")
|
|
foundInfo.urlInstaller = reader.readElementText();
|
|
if (reader.name() == "platform") {
|
|
QString plat=reader.attributes().value("id").toString();
|
|
//qDebug() << "expecting platform, read " << reader.name() << "with id" << reader.attributes().value("id").toString();
|
|
|
|
if ((plat == platform) || (plat == "all" && foundInfo.platform.length() == 0)) {
|
|
foundInfo.platform = plat;
|
|
while(reader.readNextStartElement()) {
|
|
//qDebug() << "expecting version or notes, read" << reader.name();
|
|
if (reader.name() == "version") {
|
|
QString fileVersion = reader.readElementText();
|
|
Version fv(fileVersion);
|
|
if (!fv.IsValid()) {
|
|
qWarning() << "Server file versions.xml contains an invalid version code" << fileVersion;
|
|
} else {
|
|
if (fv > getVersion())
|
|
foundInfo.version = fileVersion; // We found a more recent version
|
|
}
|
|
}
|
|
else if (reader.name() == "notes") {
|
|
foundInfo.notes = reader.readElementText();
|
|
}
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
}
|
|
else {
|
|
qWarning() << "Versions.xml file improperly formed --" << reader.errorString();
|
|
reader.raiseError(QObject::tr("New versions file improperly formed"));
|
|
}
|
|
}
|
|
return foundInfo;
|
|
}
|
|
|
|
void CheckUpdates::compareVersions () {
|
|
#ifndef NO_CHECKUPDATES
|
|
// Get any more recent versions available
|
|
VersionInfo releaseVersion = getVersionInfo ("release", platformStr());
|
|
VersionInfo testVersion = getVersionInfo ("test", platformStr());
|
|
|
|
msg = "";
|
|
if (!showTestVersion)
|
|
testVersion.version = "";
|
|
|
|
if (testVersion.version.length() == 0 && releaseVersion.version.length() == 0) {
|
|
if (showIfCurrent) {
|
|
QString txt = getVersion().IsReleaseVersion()?QObject::tr("release"):QObject::tr("test version");
|
|
QString txt2 = QObject::tr("You are running the latest %1 of OSCAR").arg(txt);
|
|
msg = txt2 + "<p>" + QObject::tr("You are running OSCAR %1").arg(getVersion()) + "</p>";
|
|
}
|
|
} else {
|
|
msg = QObject::tr("A more recent version of OSCAR is available");
|
|
msg += "<p>" + QObject::tr("You are running OSCAR %1").arg(getVersion()) + "</p>";
|
|
if (releaseVersion.version.length() > 0) {
|
|
msg += "<p>" + QObject::tr("OSCAR %1 is available <a href='%2'>here</a>.").arg(releaseVersion.version).arg(releaseVersion.urlInstaller) + "</p>";
|
|
}
|
|
if (showTestVersion && (testVersion.version.length() > 0)) {
|
|
msg += "<p>" + QObject::tr("Information about more recent test version %1 is available at <a href='%2'>%2</a>").arg(testVersion.version).arg(testVersion.urlInstaller) + "</p>";
|
|
}
|
|
}
|
|
|
|
if (msg.length() > 0) {
|
|
// Add elapsed time in test versions only
|
|
// if (elapsedTime > 0 && !getVersion().IsReleaseVersion())
|
|
// msg += "<font size='-1'><p>" + QString(QObject::tr("(Reading %1 took %2 seconds)")).arg("versions.xml").arg(elapsedTime) + "</p></font>";
|
|
msgIsReady = true;
|
|
}
|
|
|
|
AppSetting->setUpdatesLastChecked(QDateTime::currentDateTime());
|
|
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
void CheckUpdates::showMessage()
|
|
{
|
|
if (!msgIsReady)
|
|
return;
|
|
|
|
if (showIfCurrent) {
|
|
if (checkingBox != nullptr)
|
|
checkingBox->reset();
|
|
}
|
|
|
|
QMessageBox msgBox;
|
|
msgBox.setWindowTitle(QObject::tr("Check for OSCAR Updates"));
|
|
msgBox.setTextFormat(Qt::RichText);
|
|
msgBox.setText(msg);
|
|
msgBox.exec();
|
|
|
|
msgIsReady = false;
|
|
}
|
|
|
|
void CheckUpdates::checkForUpdates(bool showWhenCurrent)
|
|
{
|
|
showIfCurrent = showWhenCurrent;
|
|
showTestVersion = false;
|
|
|
|
// If running a test version of OSCAR, try reading versions.xml from OSCAR_Data directory
|
|
// and force display of any new test version
|
|
if (!getVersion().IsReleaseVersion()) {
|
|
showTestVersion = true;
|
|
versionXML = readLocalVersions();
|
|
if (versionXML.length() > 0) {
|
|
compareVersions();
|
|
elapsedTime = 0;
|
|
checkingBox = nullptr;
|
|
showMessage();
|
|
return;
|
|
}
|
|
} else {
|
|
showTestVersion = AppSetting->allowEarlyUpdates();
|
|
}
|
|
|
|
readTimer.start();
|
|
|
|
connect(manager, SIGNAL(finished(QNetworkReply*)),
|
|
this, SLOT(replyFinished(QNetworkReply*)));
|
|
|
|
manager->get(QNetworkRequest(QUrl(OSCAR_Version_File)));
|
|
|
|
if (showIfCurrent) {
|
|
checkingBox = new QProgressDialog (this);
|
|
// checkingBox->setWindowModality(Qt::WindowModal);
|
|
checkingBox->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
checkingBox->setWindowFlags(this->windowFlags() & ~Qt::WindowMinMaxButtonsHint);
|
|
checkingBox->setLabelText(tr("Checking for newer OSCAR versions"));
|
|
checkingBox->setMinimumDuration(500);
|
|
checkingBox->setRange(0,0);
|
|
checkingBox->setCancelButton(nullptr);
|
|
checkingBox->setWindowTitle(getAppName());
|
|
checkingBox->exec();
|
|
}
|
|
|
|
qDebug() << "Starting network request for" << OSCAR_Version_File;
|
|
|
|
return;
|
|
}
|
|
|
|
void CheckUpdates::replyFinished(QNetworkReply *reply)
|
|
{
|
|
if (showIfCurrent) {
|
|
if (checkingBox != nullptr)
|
|
checkingBox->reset();
|
|
}
|
|
|
|
if (reply->error() != QNetworkReply::NoError) {
|
|
qWarning() << "Update Check Error:" << reply->errorString();
|
|
reply->deleteLater();
|
|
if (!showIfCurrent) { // for automatic checks, don't show anything
|
|
return;
|
|
}
|
|
msg = QObject::tr("Unable to check for updates. Please try again later.");
|
|
msgIsReady = true;
|
|
} else {
|
|
// qDebug() << reply->header(QNetworkRequest::ContentTypeHeader).toString();
|
|
// qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
|
|
// qDebug() << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong();
|
|
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
|
|
|
versionXML = reply->readAll().toLower();
|
|
reply->deleteLater();
|
|
|
|
// Only calculate elapsed time for Help/Check for Updates
|
|
// (Auto-update time would include profile opening time)
|
|
if (showIfCurrent) {
|
|
elapsedTime = readTimer.elapsed() / 1000.0;
|
|
qDebug() << "Elapsed time to read versions.XML from web:" << elapsedTime << "seconds";
|
|
}
|
|
else
|
|
elapsedTime = 0;
|
|
|
|
compareVersions();
|
|
}
|
|
|
|
if (showIfCurrent)
|
|
showMessage();
|
|
|
|
return;
|
|
}
|