From 1e9fec270be6f23a5f1c8bfc185cd7081fcc62ec Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sun, 19 Mar 2017 17:29:20 +0100 Subject: [PATCH] Merge automatic update check into dbhub.io code Move the network part of the automatic version check code into the dbhub.io parts. While semantically this doesn't make a lot of sense it simplifies the code a bit, reduces the size of the main window class, and avoids duplication of code e.g. when introducing proxy support. --- src/MainWindow.cpp | 128 ++++++++++++++++------------------------- src/MainWindow.h | 6 +- src/RemoteDatabase.cpp | 59 ++++++++++++++----- src/RemoteDatabase.h | 4 +- 4 files changed, 100 insertions(+), 97 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index e89d101b..413e7a7a 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -28,16 +28,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include -#include -#include #include #include #include @@ -232,6 +228,7 @@ void MainWindow::init() connect(ui->dataTable->verticalHeader(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showRecordPopupMenu(QPoint))); connect(ui->dockEdit, SIGNAL(visibilityChanged(bool)), this, SLOT(toggleEditDock(bool))); connect(m_remoteDb, SIGNAL(openFile(QString)), this, SLOT(fileOpen(QString))); + connect(m_remoteDb, &RemoteDatabase::gotCurrentVersion, this, &MainWindow::checkNewVersion); // Lambda function for keyboard shortcuts for selecting next/previous table in Browse Data tab connect(ui->dataTable, &ExtendedTableWidget::switchTable, [this](bool next) { @@ -260,12 +257,8 @@ void MainWindow::init() // Check for a new version if automatic update check aren't disabled in the settings dialog if(Settings::getSettingsValue("checkversion", "enabled").toBool()) { - // Check for a new release version, usually only enabled on windows - m_NetworkManager = new QNetworkAccessManager(this); - connect(m_NetworkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpresponse(QNetworkReply*))); - - QUrl url("https://raw.githubusercontent.com/sqlitebrowser/sqlitebrowser/master/currentrelease"); - m_NetworkManager->get(QNetworkRequest(url)); + m_remoteDb->fetch("https://raw.githubusercontent.com/sqlitebrowser/sqlitebrowser/master/currentrelease", + RemoteDatabase::RequestTypeNewVersionCheck); } #endif @@ -1739,81 +1732,62 @@ void MainWindow::reloadSettings() remoteDock->reloadSettings(); } -void MainWindow::httpresponse(QNetworkReply *reply) +void MainWindow::checkNewVersion(const QString& versionstring, const QString& url) { - if(reply->error() == QNetworkReply::NoError) + // versionstring contains a major.minor.patch version string + QStringList versiontokens = versionstring.split("."); + if(versiontokens.size() < 3) + return; + + int major = versiontokens[0].toInt(); + int minor = versiontokens[1].toInt(); + int patch = versiontokens[2].toInt(); + + bool newversion = false; + if(major > MAJOR_VERSION) + newversion = true; + else if(major == MAJOR_VERSION) { - // Check for redirect - QVariant possibleRedirectUrl = - reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - - if(!possibleRedirectUrl.toUrl().isEmpty()) - { - if(reply->url() == possibleRedirectUrl.toUrl()) - return; // escape possible redirect loop - m_NetworkManager->get(QNetworkRequest(possibleRedirectUrl.toUrl())); - return; - } - - // first line of the currentrelease file contains a major.minor.patch version string - QString sversion(reply->readLine()); - - QStringList versiontokens = sversion.split("."); - if(versiontokens.size() < 3) - return; - - int major = versiontokens[0].toInt(); - int minor = versiontokens[1].toInt(); - int patch = versiontokens[2].toInt(); - - bool newversion = false; - if(major > MAJOR_VERSION) + if(minor > MINOR_VERSION) newversion = true; - else if(major == MAJOR_VERSION) + else if(minor == MINOR_VERSION) { - if(minor > MINOR_VERSION) + if(patch > PATCH_VERSION) newversion = true; - else if(minor == MINOR_VERSION) - { - if(patch > PATCH_VERSION) - newversion = true; - } - } - - if(newversion) - { - QSettings settings(QApplication::organizationName(), QApplication::organizationName()); - int ignmajor = settings.value("checkversion/ignmajor", 999).toInt(); - int ignminor = settings.value("checkversion/ignminor", 0).toInt(); - int ignpatch = settings.value("checkversion/ignpatch", 0).toInt(); - - // check if the user doesn't care about the current update - if(!(ignmajor == major && ignminor == minor && ignpatch == patch)) - { - QMessageBox msgBox; - QPushButton *idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); - msgBox.addButton(QMessageBox::Ok); - msgBox.setTextFormat(Qt::RichText); - msgBox.setWindowTitle(tr("New version available.")); - msgBox.setText(tr("A new DB Browser for SQLite version is available (%1.%2.%3).

" - "Please download at %4.").arg(major).arg(minor).arg(patch). - arg(QString(reply->readLine()).trimmed())); - msgBox.exec(); - - if(msgBox.clickedButton() == idontcarebutton) - { - // save that the user don't want to get bothered about this update - settings.beginGroup("checkversion"); - settings.setValue("ignmajor", major); - settings.setValue("ignminor", minor); - settings.setValue("ignpatch", patch); - settings.endGroup(); - } - } } } - reply->deleteLater(); + if(newversion) + { + QSettings settings(QApplication::organizationName(), QApplication::organizationName()); + int ignmajor = settings.value("checkversion/ignmajor", 999).toInt(); + int ignminor = settings.value("checkversion/ignminor", 0).toInt(); + int ignpatch = settings.value("checkversion/ignpatch", 0).toInt(); + + // check if the user doesn't care about the current update + if(!(ignmajor == major && ignminor == minor && ignpatch == patch)) + { + QMessageBox msgBox; + QPushButton *idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); + msgBox.addButton(QMessageBox::Ok); + msgBox.setTextFormat(Qt::RichText); + msgBox.setWindowTitle(tr("New version available.")); + msgBox.setText(tr("A new DB Browser for SQLite version is available (%1.%2.%3).

" + "Please download at %4.").arg(major).arg(minor).arg(patch). + arg(url)); + msgBox.exec(); + + if(msgBox.clickedButton() == idontcarebutton) + { + // save that the user don't want to get bothered about this update + settings.beginGroup("checkversion"); + settings.setValue("ignmajor", major); + settings.setValue("ignminor", minor); + settings.setValue("ignpatch", patch); + settings.endGroup(); + } + } + } } void MainWindow::on_actionSave_Remote_triggered() diff --git a/src/MainWindow.h b/src/MainWindow.h index 4783c34e..93ac5cdc 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -16,8 +16,6 @@ class QModelIndex; class QPersistentModelIndex; class SqliteTableModel; class DbStructureModel; -class QNetworkReply; -class QNetworkAccessManager; class RemoteDock; namespace Ui { @@ -149,8 +147,6 @@ private: DBBrowserDB db; QString defaultBrowseTableEncoding; - QNetworkAccessManager* m_NetworkManager; - void init(); void clearCompleterModelsFields(); @@ -226,7 +222,7 @@ private slots: void saveSqlFileAs(); void loadExtension(); void reloadSettings(); - void httpresponse(QNetworkReply* reply); + void checkNewVersion(const QString& versionstring, const QString& url); void on_actionWiki_triggered(); void on_actionBug_report_triggered(); void on_actionSqlCipherFaq_triggered(); diff --git a/src/RemoteDatabase.cpp b/src/RemoteDatabase.cpp index 2d6fb42a..86eab712 100644 --- a/src/RemoteDatabase.cpp +++ b/src/RemoteDatabase.cpp @@ -91,6 +91,21 @@ void RemoteDatabase::gotReply(QNetworkReply* reply) return; } + // Check for redirect + QString redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString(); + if(!redirectUrl.isEmpty()) + { + // Avoid redirect loop + if(reply->url() == redirectUrl) + { + reply->deleteLater(); + return; + } + fetch(redirectUrl, static_cast(reply->property("type").toInt()), reply->property("certfile").toString(), reply->property("userdata")); + reply->deleteLater(); + return; + } + // What type of data is this? RequestType type = static_cast(reply->property("type").toInt()); @@ -99,23 +114,37 @@ void RemoteDatabase::gotReply(QNetworkReply* reply) m_progress->reset(); // Handle the reply data - if(type == RequestTypeDatabase) + switch(type) { - // It's a database file. Ask user where to store the database file. - QString saveFileAs = FileDialog::getSaveFileName(0, qApp->applicationName(), FileDialog::getSqlDatabaseFileFilter(), reply->url().fileName()); - if(!saveFileAs.isEmpty()) + case RequestTypeDatabase: { - // Save the downloaded data under the selected file name - QFile file(saveFileAs); - file.open(QIODevice::WriteOnly); - file.write(reply->readAll()); - file.close(); + // It's a database file. Ask user where to store the database file. + QString saveFileAs = FileDialog::getSaveFileName(0, qApp->applicationName(), FileDialog::getSqlDatabaseFileFilter(), reply->url().fileName()); + if(!saveFileAs.isEmpty()) + { + // Save the downloaded data under the selected file name + QFile file(saveFileAs); + file.open(QIODevice::WriteOnly); + file.write(reply->readAll()); + file.close(); - // Tell the application to open this file - emit openFile(saveFileAs); + // Tell the application to open this file + emit openFile(saveFileAs); + } } - } else if(type == RequestTypeDirectory) { + break; + case RequestTypeDirectory: emit gotDirList(reply->readAll(), reply->property("userdata")); + break; + case RequestTypeNewVersionCheck: + { + QString version = reply->readLine().trimmed(); + QString url = reply->readLine().trimmed(); + emit gotCurrentVersion(version, url); + break; + } + default: + break; } // Delete reply later, i.e. after returning from this slot function @@ -261,9 +290,10 @@ void RemoteDatabase::fetch(const QString& url, RequestType type, const QString& request.setUrl(url); request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName()).arg(APP_VERSION).toUtf8()); - // Set SSL configuration when trying to access a file via the HTTPS protocol + // Set SSL configuration when trying to access a file via the HTTPS protocol. + // Skip this step when no client certificate was specified. In this case the default HTTPS configuration is used. bool https = QUrl(url).scheme().compare("https", Qt::CaseInsensitive) == 0; - if(https) + if(https && !clientCert.isNull()) { // If configuring the SSL connection fails, abort the request here if(!prepareSsl(&request, clientCert)) @@ -273,6 +303,7 @@ void RemoteDatabase::fetch(const QString& url, RequestType type, const QString& // Fetch database and save pending reply. Note that we're only supporting one active download here at the moment. m_currentReply = m_manager->get(request); m_currentReply->setProperty("type", type); + m_currentReply->setProperty("certfile", clientCert); m_currentReply->setProperty("userdata", userdata); // Initialise the progress dialog for this request, but only if this is a database file. Directory listing are small enough to be loaded diff --git a/src/RemoteDatabase.h b/src/RemoteDatabase.h index 756d5680..4423c773 100644 --- a/src/RemoteDatabase.h +++ b/src/RemoteDatabase.h @@ -28,15 +28,17 @@ public: { RequestTypeDatabase, RequestTypeDirectory, + RequestTypeNewVersionCheck, RequestTypePush, }; - void fetch(const QString& url, RequestType type, const QString& clientCert, QVariant userdata = QVariant()); + void fetch(const QString& url, RequestType type, const QString& clientCert = QString(), QVariant userdata = QVariant()); void push(const QString& filename, const QString& url, const QString& clientCert); signals: void gotDirList(QString json, QVariant userdata); void openFile(QString path); + void gotCurrentVersion(QString version, QString url); private: void gotEncrypted(QNetworkReply* reply);