diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 6aeb1c1a9..23c0842b3 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -151,6 +151,7 @@ set(SRCS ${SRCS} other/statusbar.cpp other/updater.cpp other/useragentmanager.cpp + other/protocolhandlermanager.cpp plugins/pluginproxy.cpp plugins/plugins.cpp plugins/speeddial.cpp diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 1a9c977d9..4202af601 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -46,6 +46,7 @@ #include "scripts.h" #include "sessionmanager.h" #include "closedwindowsmanager.h" +#include "protocolhandlermanager.h" #include "../config.h" #include @@ -100,6 +101,7 @@ MainApplication::MainApplication(int &argc, char** argv) , m_userAgentManager(nullptr) , m_searchEnginesManager(nullptr) , m_closedWindowsManager(nullptr) + , m_protocolHandlerManager(nullptr) , m_html5PermissionsManager(nullptr) , m_desktopNotifications(nullptr) , m_webProfile(nullptr) @@ -317,6 +319,7 @@ MainApplication::MainApplication(int &argc, char** argv) m_plugins = new PluginProxy(this); m_autoFill = new AutoFill(this); + mApp->protocolHandlerManager(); if (!noAddons) m_plugins->loadPlugins(); @@ -597,6 +600,14 @@ ClosedWindowsManager* MainApplication::closedWindowsManager() return m_closedWindowsManager; } +ProtocolHandlerManager *MainApplication::protocolHandlerManager() +{ + if (!m_protocolHandlerManager) { + m_protocolHandlerManager = new ProtocolHandlerManager(this); + } + return m_protocolHandlerManager; +} + HTML5PermissionsManager* MainApplication::html5PermissionsManager() { if (!m_html5PermissionsManager) { diff --git a/src/lib/app/mainapplication.h b/src/lib/app/mainapplication.h index 764e661d4..0b0b5d20f 100644 --- a/src/lib/app/mainapplication.h +++ b/src/lib/app/mainapplication.h @@ -52,6 +52,7 @@ class DesktopNotificationsFactory; class ProxyStyle; class SessionManager; class ClosedWindowsManager; +class ProtocolHandlerManager; class FALKON_EXPORT MainApplication : public QtSingleApplication { @@ -108,6 +109,7 @@ public: UserAgentManager* userAgentManager(); SearchEnginesManager* searchEnginesManager(); ClosedWindowsManager* closedWindowsManager(); + ProtocolHandlerManager *protocolHandlerManager(); HTML5PermissionsManager* html5PermissionsManager(); DesktopNotificationsFactory* desktopNotifications(); QWebEngineProfile* webProfile() const; @@ -182,6 +184,7 @@ private: UserAgentManager* m_userAgentManager; SearchEnginesManager* m_searchEnginesManager; ClosedWindowsManager* m_closedWindowsManager; + ProtocolHandlerManager *m_protocolHandlerManager; HTML5PermissionsManager* m_html5PermissionsManager; DesktopNotificationsFactory* m_desktopNotifications; QWebEngineProfile* m_webProfile; diff --git a/src/lib/app/settings.cpp b/src/lib/app/settings.cpp index 813f81f3d..5da6a6386 100644 --- a/src/lib/app/settings.cpp +++ b/src/lib/app/settings.cpp @@ -46,6 +46,16 @@ void Settings::syncSettings() s_settings->sync(); } +QStringList Settings::childKeys() const +{ + return s_settings->childKeys(); +} + +QStringList Settings::childGroups() const +{ + return s_settings->childGroups(); +} + bool Settings::contains(const QString &key) const { return s_settings->contains(key); diff --git a/src/lib/app/settings.h b/src/lib/app/settings.h index cc8a0d10b..9abf52aef 100644 --- a/src/lib/app/settings.h +++ b/src/lib/app/settings.h @@ -38,6 +38,9 @@ public: static QSettings* globalSettings(); static QzSettings* staticSettings(); + QStringList childKeys() const; + QStringList childGroups() const; + bool contains(const QString &key) const; void remove(const QString &key); diff --git a/src/lib/other/protocolhandlermanager.cpp b/src/lib/other/protocolhandlermanager.cpp new file mode 100644 index 000000000..ccf9078b2 --- /dev/null +++ b/src/lib/other/protocolhandlermanager.cpp @@ -0,0 +1,92 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2019 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "protocolhandlermanager.h" +#include "settings.h" + +#include +#include + +#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#include +#endif + +ProtocolHandlerManager::ProtocolHandlerManager(QObject *parent) + : QObject(parent) +{ + init(); +} + +QHash ProtocolHandlerManager::protocolHandlers() const +{ + return m_protocolHandlers; +} + +void ProtocolHandlerManager::addProtocolHandler(const QString &scheme, const QUrl &url) +{ + if (scheme.isEmpty() || url.isEmpty()) { + return; + } + m_protocolHandlers[scheme] = url; + registerHandler(scheme, url); + save(); +} + +void ProtocolHandlerManager::removeProtocolHandler(const QString &scheme) +{ + m_protocolHandlers.remove(scheme); + save(); +} + +void ProtocolHandlerManager::init() +{ + Settings settings; + settings.beginGroup(QSL("ProtocolHandlers")); + const QStringList keys = settings.childKeys(); + for (const QString &scheme : keys) { + const QUrl url = settings.value(scheme).toUrl(); + m_protocolHandlers[scheme] = url; + registerHandler(scheme, url); + } + settings.endGroup(); +} + +void ProtocolHandlerManager::save() +{ + Settings settings; + settings.remove(QSL("ProtocolHandlers")); + settings.beginGroup(QSL("ProtocolHandlers")); + for (auto it = m_protocolHandlers.cbegin(); it != m_protocolHandlers.cend(); ++it) { + settings.setValue(it.key(), it.value()); + } + settings.endGroup(); +} + +void ProtocolHandlerManager::registerHandler(const QString &scheme, const QUrl &url) +{ + QString urlString = url.toString(); + urlString.replace(QL1S("%25s"), QL1S("%s")); + + QWebEnginePage *page = new QWebEnginePage(this); + connect(page, &QWebEnginePage::loadFinished, page, &QObject::deleteLater); +#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0) + connect(page, &QWebEnginePage::registerProtocolHandlerRequested, this, [](QWebEngineRegisterProtocolHandlerRequest request) { + request.accept(); + }); +#endif + page->setHtml(QSL("").arg(scheme, urlString), url); +} diff --git a/src/lib/other/protocolhandlermanager.h b/src/lib/other/protocolhandlermanager.h new file mode 100644 index 000000000..71191d0a9 --- /dev/null +++ b/src/lib/other/protocolhandlermanager.h @@ -0,0 +1,44 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2019 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#pragma once + +#include +#include +#include + +#include "qzcommon.h" + +class FALKON_EXPORT ProtocolHandlerManager : public QObject +{ + Q_OBJECT + +public: + explicit ProtocolHandlerManager(QObject *parent = nullptr); + + QHash protocolHandlers() const; + + void addProtocolHandler(const QString &scheme, const QUrl &url); + void removeProtocolHandler(const QString &scheme); + +private: + void init(); + void save(); + void registerHandler(const QString &scheme, const QUrl &url); + + QHash m_protocolHandlers; +}; diff --git a/src/lib/other/siteinfowidget.cpp b/src/lib/other/siteinfowidget.cpp index 480241ea1..4e8dde030 100644 --- a/src/lib/other/siteinfowidget.cpp +++ b/src/lib/other/siteinfowidget.cpp @@ -23,6 +23,7 @@ #include "webpage.h" #include "tabbedwebview.h" #include "sqldatabase.h" +#include "protocolhandlermanager.h" #include @@ -83,10 +84,38 @@ SiteInfoWidget::SiteInfoWidget(BrowserWindow* window, QWidget* parent) } } + updateProtocolHandler(); + connect(ui->pushButton, &QAbstractButton::clicked, m_window->action(QSL("Tools/SiteInfo")), &QAction::trigger); + connect(ui->protocolHandlerButton, &QPushButton::clicked, this, &SiteInfoWidget::protocolHandlerButtonClicked); } SiteInfoWidget::~SiteInfoWidget() { delete ui; } + +void SiteInfoWidget::updateProtocolHandler() +{ + WebPage *page = m_window->weView()->page(); + + const QString scheme = page->registerProtocolHandlerRequestScheme(); + const QUrl registeredUrl = mApp->protocolHandlerManager()->protocolHandlers().value(scheme); + + if (!scheme.isEmpty() && registeredUrl != page->registerProtocolHandlerRequestUrl()) { + ui->protocolHandlerLabel->setText(tr("Register as %1 links handler").arg(page->registerProtocolHandlerRequestScheme())); + ui->protocolHandlerButton->setText(tr("Register")); + } else { + ui->protocolHandlerLabel->hide(); + ui->protocolHandlerButton->hide(); + ui->protocolHandlerLine->hide(); + } +} + +void SiteInfoWidget::protocolHandlerButtonClicked() +{ + WebPage *page = m_window->weView()->page(); + + mApp->protocolHandlerManager()->addProtocolHandler(page->registerProtocolHandlerRequestScheme(), page->registerProtocolHandlerRequestUrl()); + close(); +} diff --git a/src/lib/other/siteinfowidget.h b/src/lib/other/siteinfowidget.h index 416df5c70..fe2cdb4a6 100644 --- a/src/lib/other/siteinfowidget.h +++ b/src/lib/other/siteinfowidget.h @@ -38,6 +38,9 @@ public: ~SiteInfoWidget(); private: + void updateProtocolHandler(); + void protocolHandlerButtonClicked(); + Ui::SiteInfoWidget* ui; BrowserWindow* m_window; }; diff --git a/src/lib/other/siteinfowidget.ui b/src/lib/other/siteinfowidget.ui index 8de90f119..acfd8320d 100644 --- a/src/lib/other/siteinfowidget.ui +++ b/src/lib/other/siteinfowidget.ui @@ -38,7 +38,7 @@ 15 - + 6 @@ -75,23 +75,15 @@ - - - - - + - - - - - - - - + - - + + + 0 + 0 + @@ -102,20 +94,6 @@ - - - - Qt::Horizontal - - - - - - - - - - @@ -123,6 +101,50 @@ + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + + + + + + + + + + 0 + 0 + + + + + + diff --git a/src/lib/webengine/webpage.cpp b/src/lib/webengine/webpage.cpp index 54cb72579..55853b2eb 100644 --- a/src/lib/webengine/webpage.cpp +++ b/src/lib/webengine/webpage.cpp @@ -59,6 +59,10 @@ #include #include +#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#include +#endif + QString WebPage::s_lastUploadLocation = QDir::homePath(); QUrl WebPage::s_lastUnsupportedUrl; QTime WebPage::s_lastUnsupportedUrlTime; @@ -111,6 +115,13 @@ WebPage::WebPage(QObject* parent) } }); +#if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 11, 0) + connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, [this](QWebEngineRegisterProtocolHandlerRequest request) { + delete m_registerProtocolHandlerRequest; + m_registerProtocolHandlerRequest = new QWebEngineRegisterProtocolHandlerRequest(request); + }); +#endif + #if QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 12, 0) connect(this, &QWebEnginePage::printRequested, this, &WebPage::printRequested); connect(this, &QWebEnginePage::selectClientCertificate, this, [this](QWebEngineClientCertificateSelection selection) { @@ -122,6 +133,8 @@ WebPage::WebPage(QObject* parent) WebPage::~WebPage() { + delete m_registerProtocolHandlerRequest; + if (m_runningLoop) { m_runningLoop->exit(1); m_runningLoop = 0; @@ -491,6 +504,22 @@ QStringList WebPage::autoFillUsernames() const return m_autoFillUsernames; } +QUrl WebPage::registerProtocolHandlerRequestUrl() const +{ + if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) { + return m_registerProtocolHandlerRequest->origin(); + } + return QUrl(); +} + +QString WebPage::registerProtocolHandlerRequestScheme() const +{ + if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) { + return m_registerProtocolHandlerRequest->scheme(); + } + return QString(); +} + bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) { if (!kEnableJsNonBlockDialogs) { diff --git a/src/lib/webengine/webpage.h b/src/lib/webengine/webpage.h index f3f2c1be1..0b1aa8944 100644 --- a/src/lib/webengine/webpage.h +++ b/src/lib/webengine/webpage.h @@ -27,6 +27,7 @@ class QEventLoop; class QWebEngineDownloadItem; +class QWebEngineRegisterProtocolHandlerRequest; class WebView; class WebHitTestResult; @@ -63,6 +64,9 @@ public: QStringList autoFillUsernames() const; + QUrl registerProtocolHandlerRequestUrl() const; + QString registerProtocolHandlerRequestScheme() const; + bool isRunningLoop(); bool isLoading() const; @@ -106,6 +110,7 @@ private: QEventLoop* m_runningLoop; QStringList m_autoFillUsernames; + QWebEngineRegisterProtocolHandlerRequest *m_registerProtocolHandlerRequest = nullptr; int m_loadProgress; bool m_blockAlerts;