diff --git a/src/core/UBApplicationController.cpp b/src/core/UBApplicationController.cpp index 36ae40ca..5ae365a2 100644 --- a/src/core/UBApplicationController.cpp +++ b/src/core/UBApplicationController.cpp @@ -90,7 +90,6 @@ UBApplicationController::UBApplicationController(UBBoardView *pControlView, , mAutomaticCheckForUpdates(false) , mCheckingForUpdates(false) , mIsShowingDesktop(false) - , mHttp(0) { mDisplayManager = new UBDisplayManager(this); @@ -121,7 +120,7 @@ UBApplicationController::UBApplicationController(UBBoardView *pControlView, connect(UBApplication::webController, SIGNAL(imageCaptured(const QPixmap &, bool, const QUrl&)) , this, SLOT(addCapturedPixmap(const QPixmap &, bool, const QUrl&))); - networkAccessManager = new QNetworkAccessManager (this); + mNetworkAccessManager = new QNetworkAccessManager (this); QTimer::singleShot (1000, this, SLOT (checkAtLaunch())); } @@ -136,8 +135,6 @@ UBApplicationController::~UBApplicationController() delete mBlackScene; delete mMirror; - if (mHttp) delete mHttp; - delete(mOpenSankoreImporter); mOpenSankoreImporter = NULL; } @@ -478,85 +475,71 @@ void UBApplicationController::showDesktop(bool dontSwitchFrontProcess) } -void UBApplicationController::checkUpdate(QString urlString) +void UBApplicationController::checkUpdate(const QUrl& url) { + QUrl jsonUrl = url; + if (url.isEmpty()) + jsonUrl = UBSettings::settings()->appSoftwareUpdateURI->get().toUrl(); + qDebug() << "Checking for update at url: " << jsonUrl.toString(); - #if defined(QT_NO_DEBUG) - /* - if(mHttp) - mHttp->deleteLater(); - QUrl url(urlString); - mHttp = new QHttpPart(url.host()); - connect(mHttp, SIGNAL(requestFinished(int,bool)), this, SLOT(updateRequestFinished(int,bool))); - connect(mHttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(updateHeaderReceived(QHttpResponseHeader))); - - mHttp->get(url.path()); - - */ - -#else - if(mHttpreply) - mHttpreply->deleteLater(); - QUrl url(urlString); - mHttpreply = qnam.get(QNetworkRequest(url)); - connect(mHttpreply, SIGNAL(requestFinished(int,bool)), this, SLOT(updateRequestFinished(int,bool))); - connect(mHttpreply, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(updateHeaderReceived(QHttpResponseHeader))); - // mHttpreply->setUrl(url.path()); - //mHttp->get(url.path()); + connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(updateRequestFinished(QNetworkReply*))); + + mNetworkAccessManager->get(QNetworkRequest(jsonUrl)); -#endif } -/* -void UBApplicationController::updateHeaderReceived(QHttpResponseHeader header) + + +void UBApplicationController::updateRequestFinished(QNetworkReply * reply) { - if(header.statusCode() == 302 && header.hasKey("Location")){ - mHttp->close(); - checkUpdate(header.value("Location")); + if (reply->error()) { + qWarning() << "Error downloading update file: " << reply->errorString(); + return; } -} -*/ -void UBApplicationController::updateHeaderReceived(QNetworkRequest header ) -{ - //if(header.attribute(QNetworkRequest::HttpStatusCodeAttribute) == 302 && header.header(QNetworkRequest::LocationHeader)){ - // mHttp->close(); - mHttpreply->close(); - //checkUpdate(header.value("Location")); - // } -} + // Check if we are being redirected. If so, call checkUpdate again -void UBApplicationController::updateRequestFinished(int id, bool error) -{ - if (error){ - qWarning() << "http command id" << id << "return an error"; - } - else{ - /* QString responseString = QString(mHttp->readAll()); - qDebug() << responseString; - if (!responseString.isEmpty() && responseString.contains("version") && responseString.contains("url")){ - mHttp->close(); - mHttp->deleteLater(); - mHttp = 0; - downloadJsonFinished(responseString); - } - */ - QString responseString = QString(mHttpreply->readAll()); - qDebug() << responseString; - if (!responseString.isEmpty() && responseString.contains("version") && responseString.contains("url")){ - mHttpreply->close(); - mHttpreply->deleteLater(); - mHttpreply = 0; - downloadJsonFinished(responseString); - } - } -} + QVariant redirect_target = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (!redirect_target.isNull()) { + // The returned URL might be relative. resolved() creates an absolute url from it + QUrl redirect_url(reply->url().resolved(redirect_target.toUrl())); + checkUpdate(redirect_url); + return; + } + + // No error and no redirect => we read the whole response + + QString responseString = QString(reply->readAll()); + + if (!responseString.isEmpty() && + responseString.contains("version") && + responseString.contains("url")) { + + reply->close(); + reply->deleteLater(); + + downloadJsonFinished(responseString); + } +} void UBApplicationController::downloadJsonFinished(QString currentJson) { + /* + The .json files simply specify the latest version number available, and + the URL to send the user to, so they can download it. + + They look like: + + { + "version": "1.3.5", + "url": "http://openboard.ch" + } + */ + QScriptValue scriptValue; QScriptEngine scriptEngine; scriptValue = scriptEngine.evaluate ("(" + currentJson + ")"); @@ -564,17 +547,18 @@ void UBApplicationController::downloadJsonFinished(QString currentJson) UBVersion installedVersion (qApp->applicationVersion()); UBVersion jsonVersion (scriptValue.property("version").toString()); + qDebug() << "json version: " << jsonVersion.toUInt(); + qDebug() << "installed version: " << installedVersion.toUInt(); + if (jsonVersion > installedVersion) { - if (UBApplication::mainWindow->yesNoQuestion(tr("Update available"), tr ("New update available, would you go to the web page ?"))){ - QUrl url(scriptValue.property ("url").toString()); - QDesktopServices::openUrl (url); - } - } - else { - if (isNoUpdateDisplayed) { - mMainWindow->information(tr("Update"), tr("No update available")); + if (UBApplication::mainWindow->yesNoQuestion(tr("Update available"), tr ("New update available, would you go to the web page ?"))){ + QUrl url(scriptValue.property("url").toString()); + QDesktopServices::openUrl(url); } } + else if (isNoUpdateDisplayed) { + mMainWindow->information(tr("Update"), tr("No update available")); + } } void UBApplicationController::checkAtLaunch() @@ -583,14 +567,14 @@ void UBApplicationController::checkAtLaunch() if(UBSettings::settings()->appEnableAutomaticSoftwareUpdates->get().toBool()){ isNoUpdateDisplayed = false; - //checkUpdate (); + checkUpdate(); } } void UBApplicationController::checkUpdateRequest() { isNoUpdateDisplayed = true; - //checkUpdate (); + checkUpdate(); } void UBApplicationController::hideDesktop() diff --git a/src/core/UBApplicationController.h b/src/core/UBApplicationController.h index 03ace3a9..c3cfb40d 100644 --- a/src/core/UBApplicationController.h +++ b/src/core/UBApplicationController.h @@ -53,12 +53,8 @@ class UBVersion; class UBSoftwareUpdate; class QNetworkAccessManager; class QNetworkReply; -class QHttpPart; class UBRightPalette; class UBOpenSankoreImporter; -class QScriptValue; -class QScriptEngine; -class QNetworkReply; class UBApplicationController : public QObject { @@ -158,8 +154,8 @@ class UBApplicationController : public QObject void checkAtLaunch(); private slots: - void updateRequestFinished(int id, bool error); - void updateHeaderReceived(QNetworkRequest header ); + void updateRequestFinished(QNetworkReply * reply); + protected: @@ -193,13 +189,10 @@ class UBApplicationController : public QObject bool mIsShowingDesktop; bool isNoUpdateDisplayed; - void checkUpdate (QString urlString = "http://get.openboard.org/update.json"); - QNetworkAccessManager *networkAccessManager; + void checkUpdate(const QUrl &url = QUrl()); + QNetworkAccessManager * mNetworkAccessManager; void downloadJsonFinished(QString updateString); - QHttpPart* mHttp; - QNetworkAccessManager qnam; - QNetworkReply *mHttpreply; }; #endif /* UBAPPLICATIONCONTROLLER_H_ */ diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index cccf87b7..4b657602 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -226,6 +226,7 @@ void UBSettings::init() appToolBarDisplayText = new UBSetting(this, "App", "ToolBarDisplayText", true); appEnableAutomaticSoftwareUpdates = new UBSetting(this, "App", "EnableAutomaticSoftwareUpdates", false); appEnableSoftwareUpdates = new UBSetting(this, "App", "EnableSoftwareUpdates", true); + appSoftwareUpdateURI = new UBSetting(this, "App", "SoftwareUpdateURI", "http://www.openboard.ch/update.json"); appToolBarOrientationVertical = new UBSetting(this, "App", "ToolBarOrientationVertical", false); appPreferredLanguage = new UBSetting(this,"App","PreferredLanguage", ""); diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index 9f024d57..4e3f0ec5 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -240,6 +240,7 @@ class UBSettings : public QObject UBSetting* appToolBarDisplayText; UBSetting* appEnableAutomaticSoftwareUpdates; UBSetting* appEnableSoftwareUpdates; + UBSetting* appSoftwareUpdateURI; UBSetting* appToolBarOrientationVertical; UBSetting* appPreferredLanguage; diff --git a/src/frameworks/UBVersion.cpp b/src/frameworks/UBVersion.cpp index a08c4fc7..b8916152 100644 --- a/src/frameworks/UBVersion.cpp +++ b/src/frameworks/UBVersion.cpp @@ -42,21 +42,32 @@ UBVersion::UBVersion(const QString &string) uint UBVersion::toUInt() const { + /* Based on semantic versioning, version numbers look like: + * Major.Minor.Patch-Type.Build + * + * To compare version numbers, the string is split into each part, and they are multiplied + * to give a number where the first two digits are the Major version, the next two are the + * Minor version, and so on. + * + * i.e if Major, Minor etc. are named A, B, C, D, E, the number will look like: + * AABBCCDDEE + */ + uint result = 0; - QStringList list = mString.split("."); + QStringList list = mString.split(QRegExp("[-\\.]")); switch (list.count()) { case 2: //short version 1.0 - result = (list.at(0).toUInt() * 1000000) + (list.at(1).toUInt() * 10000) + (Release * 100); + result = (list.at(0).toUInt() * 100000000) + (list.at(1).toUInt() * 1000000) + (Release * 100); break; case 3: //release version 1.0.0 - result = (list.at(0).toUInt() * 1000000) + (list.at(1).toUInt() * 10000) + (Release * 100) + list.at(2).toUInt(); + result = (list.at(0).toUInt() * 100000000) + (list.at(1).toUInt() * 1000000) + list.at(2).toUInt()*10000 + (Release * 100); break; - case 4:{ - //standard version 1.0.a/b/r.0 - uint releaseStage = list.at(2).startsWith("a") ? Alpha :(list.at(2).startsWith("b") ? Beta : ReleaseCandidate); - result = (list.at(0).toUInt() * 1000000) + (list.at(1).toUInt() * 10000) + (releaseStage * 100) + list.at(3).toUInt(); + case 5:{ + //standard version 1.0.0.a/b/rc.0 + uint releaseStage = list.at(3).startsWith("a") ? Alpha :(list.at(3).startsWith("b") ? Beta : ReleaseCandidate); + result = (list.at(0).toUInt() * 100000000) + (list.at(1).toUInt() * 1000000) + (list.at(2).toUInt() * 10000) + (releaseStage * 100) + list.at(4).toUInt(); break; } default: