diff --git a/connector/syncthingconnection.cpp b/connector/syncthingconnection.cpp index 731c7bf..503a7f7 100644 --- a/connector/syncthingconnection.cpp +++ b/connector/syncthingconnection.cpp @@ -138,6 +138,18 @@ void SyncthingConnection::connect() } } +/*! + * \brief Applies the specified configuration and tries to reconnect via reconnect() if properties requiring reconnect + * to take effect have changed. + * \remarks The expected SSL errors of the specified configuration are updated accordingly. + */ +void SyncthingConnection::connect(SyncthingConnectionSettings &connectionSettings) +{ + if(applySettings(connectionSettings)) { + reconnect(); + } +} + /*! * \brief Disconnects. Does nothing if not connected. */ @@ -620,8 +632,9 @@ QMetaObject::Connection SyncthingConnection::requestLog(std::function cert = QSslCertificate::fromPath(certPath); - if(cert.isEmpty()) { + const QList certs = QSslCertificate::fromPath(certPath); + if(certs.isEmpty()) { emit error(tr("Unable to load certificate used by Syncthing GUI."), SyncthingErrorCategory::OverallConnection); - return; + return false; } + const QSslCertificate &cert = certs.at(0); m_expectedSslErrors.reserve(4); - m_expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert.at(0)); - m_expectedSslErrors << QSslError(QSslError::UnableToVerifyFirstCertificate, cert.at(0)); - m_expectedSslErrors << QSslError(QSslError::SelfSignedCertificate, cert.at(0)); - m_expectedSslErrors << QSslError(QSslError::HostNameMismatch, cert.at(0)); + m_expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert) + << QSslError(QSslError::UnableToVerifyFirstCertificate, cert) + << QSslError(QSslError::SelfSignedCertificate, cert) + << QSslError(QSslError::HostNameMismatch, cert); + return true; } /*! @@ -661,26 +676,46 @@ void SyncthingConnection::loadSelfSignedCertificate() * \remarks * - The expected SSL errors of the specified configuration are updated accordingly. * - The configuration is not used instantly. It will be used on the next reconnect. + * \returns Returns whether at least one property requiring a reconnect to take effect has changed. * \sa reconnect() */ -void SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionSettings) +bool SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionSettings) { - setSyncthingUrl(connectionSettings.syncthingUrl); - setApiKey(connectionSettings.apiKey); - if(connectionSettings.authEnabled) { - setCredentials(connectionSettings.userName, connectionSettings.password); - } else { - setCredentials(QString(), QString()); + bool reconnectRequired = false; + if(syncthingUrl() != connectionSettings.syncthingUrl) { + setSyncthingUrl(connectionSettings.syncthingUrl); + reconnectRequired = true; } + if(apiKey() != connectionSettings.apiKey) { + setApiKey(connectionSettings.apiKey); + reconnectRequired = true; + } + if((connectionSettings.authEnabled && (user() != connectionSettings.userName || password() != connectionSettings.password)) + || (!connectionSettings.authEnabled && (!user().isEmpty() || !password().isEmpty()))) { + if(connectionSettings.authEnabled) { + setCredentials(connectionSettings.userName, connectionSettings.password); + } else { + setCredentials(QString(), QString()); + } + reconnectRequired = true; + } + if(connectionSettings.expectedSslErrors.isEmpty()) { + const bool previouslyHadExpectedSslErrors = !expectedSslErrors().isEmpty(); + const bool ok = loadSelfSignedCertificate(); + connectionSettings.expectedSslErrors = expectedSslErrors(); + if(ok || (previouslyHadExpectedSslErrors && !ok)) { + reconnectRequired = true; + } + } else if(expectedSslErrors() != connectionSettings.expectedSslErrors) { + m_expectedSslErrors = connectionSettings.expectedSslErrors; + reconnectRequired = true; + } + setTrafficPollInterval(connectionSettings.trafficPollInterval); setDevStatsPollInterval(connectionSettings.devStatsPollInterval); setAutoReconnectInterval(connectionSettings.reconnectInterval); - if(connectionSettings.expectedSslErrors.isEmpty()) { - loadSelfSignedCertificate(); - connectionSettings.expectedSslErrors = expectedSslErrors(); - } else { - m_expectedSslErrors = connectionSettings.expectedSslErrors; - } + + return reconnectRequired; } /*! diff --git a/connector/syncthingconnection.h b/connector/syncthingconnection.h index fb49d00..1e67033 100644 --- a/connector/syncthingconnection.h +++ b/connector/syncthingconnection.h @@ -111,9 +111,10 @@ public: const std::vector &completedDirs() const; public Q_SLOTS: - void loadSelfSignedCertificate(); - void applySettings(SyncthingConnectionSettings &connectionSettings); + bool loadSelfSignedCertificate(); + bool applySettings(SyncthingConnectionSettings &connectionSettings); void connect(); + void connect(SyncthingConnectionSettings &connectionSettings); void disconnect(); void reconnect(); void reconnect(SyncthingConnectionSettings &connectionSettings); diff --git a/tray/gui/trayicon.cpp b/tray/gui/trayicon.cpp index 0bd1966..0c182cf 100644 --- a/tray/gui/trayicon.cpp +++ b/tray/gui/trayicon.cpp @@ -61,7 +61,7 @@ TrayIcon::TrayIcon(QObject *parent) : // setup notifications m_disconnectedNotification.setMessage(tr("Disconnected from Syncthing")); m_disconnectedNotification.setActions(QStringList(tr("Try to reconnect"))); - connect(&m_disconnectedNotification, &DBusNotification::actionInvoked, &(m_trayMenu.widget()->connection()), &SyncthingConnection::connect); + connect(&m_disconnectedNotification, &DBusNotification::actionInvoked, &(m_trayMenu.widget()->connection()), static_cast(&SyncthingConnection::connect)); m_syncthingNotification.setActions(QStringList({QStringLiteral("show"), tr("Show"), QStringLiteral("dismiss"), tr("Dismiss")})); connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &TrayIcon::handleSyncthingNotificationAction); #endif diff --git a/tray/gui/traywidget.cpp b/tray/gui/traywidget.cpp index 4ba9edf..4d7e3c8 100644 --- a/tray/gui/traywidget.cpp +++ b/tray/gui/traywidget.cpp @@ -375,7 +375,7 @@ void TrayWidget::applySettings() instance->m_connectionsMenu->actions().at(0)->setChecked(true); } instance->m_ui->connectionsPushButton->setText(instance->m_selectedConnection->label); - instance->m_connection.reconnect(*instance->m_selectedConnection); + instance->m_connection.connect(*instance->m_selectedConnection); // web view #ifndef SYNCTHINGTRAY_NO_WEBVIEW diff --git a/tray/gui/webpage.cpp b/tray/gui/webpage.cpp index a0e2737..07f4b40 100644 --- a/tray/gui/webpage.cpp +++ b/tray/gui/webpage.cpp @@ -57,6 +57,26 @@ WebPage::WebPage(WebViewDialog *dlg, WEB_VIEW_PROVIDER *view) : } } +bool WebPage::isSamePage(const QUrl &url1, const QUrl &url2) +{ + if(url1.scheme() == url2.scheme() + && url1.host() == url2.host() + && url1.port() == url2.port()) { + QString path1 = url1.path(); + while(path1.endsWith(QChar('/'))) { + path1.resize(path1.size() - 1); + } + QString path2 = url2.path(); + while(path2.endsWith(QChar('/'))) { + path2.resize(path2.size() - 1); + } + if(path1 == path2) { + return true; + } + } + return false; +} + WEB_PAGE_PROVIDER *WebPage::createWindow(WEB_PAGE_PROVIDER::WebWindowType type) { Q_UNUSED(type) @@ -128,20 +148,8 @@ bool WebPage::handleNavigationRequest(const QUrl ¤tUrl, const QUrl &target return true; } // only allow navigation on the same page - if(currentUrl.scheme() == targetUrl.scheme() - && currentUrl.host() == targetUrl.host() - && currentUrl.port() == targetUrl.port()) { - QString currentPath = currentUrl.path(); - while(currentPath.endsWith(QChar('/'))) { - currentPath.resize(currentPath.size() - 1); - } - QString targetPath = targetUrl.path(); - while(targetPath.endsWith(QChar('/'))) { - targetPath.resize(targetPath.size() - 1); - } - if(currentPath == targetPath) { - return true; - } + if(isSamePage(currentUrl, targetUrl)) { + return true; } // otherwise open URL in external browser QDesktopServices::openUrl(targetUrl); diff --git a/tray/gui/webpage.h b/tray/gui/webpage.h index c8a7890..321cb88 100644 --- a/tray/gui/webpage.h +++ b/tray/gui/webpage.h @@ -26,6 +26,8 @@ class WebPage : public WEB_PAGE_PROVIDER public: WebPage(WebViewDialog *dlg = nullptr, WEB_VIEW_PROVIDER *view = nullptr); + static bool isSamePage(const QUrl &url1, const QUrl &url2); + protected: WEB_PAGE_PROVIDER *createWindow(WebWindowType type); #ifdef SYNCTHINGTRAY_USE_WEBENGINE @@ -45,7 +47,7 @@ private slots: #endif private: - bool handleNavigationRequest(const QUrl ¤tUrl, const QUrl &url); + static bool handleNavigationRequest(const QUrl ¤tUrl, const QUrl &url); WebViewDialog *m_dlg; WEB_VIEW_PROVIDER *m_view; diff --git a/tray/gui/webviewdialog.cpp b/tray/gui/webviewdialog.cpp index ef1e200..ac4f8cc 100644 --- a/tray/gui/webviewdialog.cpp +++ b/tray/gui/webviewdialog.cpp @@ -54,7 +54,9 @@ QtGui::WebViewDialog::~WebViewDialog() void QtGui::WebViewDialog::applySettings(const Data::SyncthingConnectionSettings &connectionSettings) { m_settings = connectionSettings; - m_view->setUrl(connectionSettings.syncthingUrl); + if(!WebPage::isSamePage(m_view->url(), connectionSettings.syncthingUrl)) { + m_view->setUrl(connectionSettings.syncthingUrl); + } m_view->setZoomFactor(Settings::values().webView.zoomFactor); }