1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 02:36:34 +01:00

OcsSupport: Add initial support for downloading themes/extensions

This commit is contained in:
David Rosca 2019-04-18 16:25:27 +02:00
parent 13449605eb
commit 5e6f92f7bc
No known key found for this signature in database
GPG Key ID: EBC3FC294452C6D8
9 changed files with 280 additions and 2 deletions

View File

@ -88,6 +88,9 @@ endif()
# Mandatory: OpenSSL
find_package(OpenSSL REQUIRED)
# Mandatory: KF5
find_package(KF5 REQUIRED COMPONENTS Archive)
# KF5I18n: Mandatory with downloaded translations (only for ki18n_install)
if (EXISTS "${CMAKE_SOURCE_DIR}/po")
find_package(KF5I18n REQUIRED)

View File

@ -156,6 +156,7 @@ set(SRCS ${SRCS}
plugins/pluginproxy.cpp
plugins/plugins.cpp
plugins/speeddial.cpp
plugins/ocssupport.cpp
plugins/qml/qmlpluginloader.cpp
plugins/qml/qmlplugin.cpp
plugins/qml/qmlplugins.cpp
@ -348,6 +349,7 @@ target_link_libraries(FalkonPrivate
Qt5::PrintSupport
Qt5::QuickWidgets
Qt5::WebChannel
KF5::Archive
${OPENSSL_CRYPTO_LIBRARY}
)

View File

@ -61,6 +61,11 @@ bool DesktopNotificationsFactory::supportsNativeNotifications() const
#endif
}
void DesktopNotificationsFactory::showNotification(const QString &heading, const QString &text)
{
showNotification(QPixmap(), heading, text);
}
void DesktopNotificationsFactory::showNotification(const QPixmap &icon, const QString &heading, const QString &text)
{
if (!m_enabled) {

View File

@ -43,6 +43,7 @@ public:
bool supportsNativeNotifications() const;
void showNotification(const QString &heading, const QString &text);
void showNotification(const QPixmap &icon, const QString &heading, const QString &text);
void nativeNotificationPreview();

View File

@ -0,0 +1,206 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 David Rosca <nowrep@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "ocssupport.h"
#include "pluginproxy.h"
#include "datapaths.h"
#include "networkmanager.h"
#include "desktopnotificationsfactory.h"
#include "mainapplication.h"
#include <QDir>
#include <QBuffer>
#include <QUrlQuery>
#include <QNetworkReply>
#include <KArchive/KZip>
Q_GLOBAL_STATIC(OcsSupport, qz_ocs_support)
OcsSupport::OcsSupport(QObject *parent)
: QObject(parent)
{
}
bool OcsSupport::handleUrl(const QUrl &url)
{
if (url.host() != QL1S("install")) {
return false;
}
QUrl fileUrl;
QString fileType;
QString fileName;
const auto items = QUrlQuery(url).queryItems(QUrl::FullyDecoded);
for (const auto &item : items) {
if (item.first == QL1S("url")) {
fileUrl = QUrl(item.second);
} else if (item.first == QL1S("type")) {
fileType = item.second;
} else if (item.first == QL1S("filename")) {
fileName = item.second;
}
}
if (!fileType.startsWith(QL1S("falkon_"))) {
return false;
}
if (fileType != QL1S("falkon_themes") && fileType != QL1S("falkon_extensions")) {
qWarning() << "Unsupported type" << fileType;
return false;
}
if (!fileUrl.isValid()) {
qWarning() << "Invalid url" << fileUrl << url;
return false;
}
qInfo() << "Downloading" << fileUrl;
QNetworkReply *reply = mApp->networkManager()->get(QNetworkRequest(fileUrl));
connect(reply, &QNetworkReply::finished, this, [=]() {
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "Error downloading" << fileUrl << reply->error() << reply->errorString();
return;
}
QBuffer buf;
buf.setData(reply->readAll());
KZip zip(&buf);
if (!zip.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open archive";
return;
}
QString notifyMessage;
if (fileType == QL1S("falkon_themes")) {
installTheme(zip.directory());
} else if (fileType == QL1S("falkon_extensions")) {
installExtension(zip.directory());
}
});
return true;
}
// static
OcsSupport *OcsSupport::instance()
{
return qz_ocs_support();
}
void OcsSupport::installTheme(const KArchiveDirectory *directory)
{
auto showError = []() {
mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Failed to install theme"));
};
if (directory->entries().size() != 1) {
qWarning() << "Invalid archive format";
showError();
return;
}
const QString name = directory->entries().at(0);
const KArchiveEntry *entry = directory->entry(name);
if (!entry || !entry->isDirectory()) {
qWarning() << "Invalid archive format";
showError();
return;
}
const QString targetDir = DataPaths::path(DataPaths::Config) + QL1S("/themes");
QDir().mkpath(targetDir);
if (QFileInfo::exists(targetDir + QL1C('/') + name)) {
qWarning() << "Theme" << name << "already exists";
mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Theme is already installed"));
return;
}
if (!directory->copyTo(targetDir)) {
qWarning() << "Failed to copy theme to" << targetDir;
showError();
return;
}
qInfo() << "Theme installed to" << targetDir;
mApp->desktopNotifications()->showNotification(tr("Theme installed"), tr("Theme was successfully installed"));
}
void OcsSupport::installExtension(const KArchiveDirectory *directory)
{
auto showError = []() {
mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Failed to install extension"));
};
if (directory->entries().size() != 1) {
qWarning() << "Invalid archive format";
showError();
return;
}
const QString name = directory->entries().at(0);
const KArchiveEntry *entry = directory->entry(name);
if (!entry || !entry->isDirectory()) {
qWarning() << "Invalid archive format";
showError();
return;
}
QString type;
const QStringList files = static_cast<const KArchiveDirectory*>(entry)->entries();
if (files.contains(QL1S("__init__.py"))) {
type = QSL("python");
} else if (files.contains(QL1S("main.qml"))) {
type = QSL("qml");
}
if (type.isEmpty()) {
qWarning() << "Unsupported extension type";
showError();
return;
}
const QString targetDir = DataPaths::path(DataPaths::Config) + QL1S("/plugins/") + type;
QDir().mkpath(targetDir);
if (QFileInfo::exists(targetDir + QL1S("/") + name)) {
qWarning() << "Extension" << name << "already exists";
mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Extension is already installed"));
return;
}
if (!directory->copyTo(targetDir)) {
qWarning() << "Failed to copy extension to" << targetDir;
showError();
return;
}
qInfo() << "Extension installed to" << targetDir;
const QString fullId = QSL("%1:%2/%3").arg(type, targetDir, name);
if (!mApp->plugins()->addPlugin(fullId)) {
qWarning() << "Failed to add plugin" << fullId;
showError();
return;
}
mApp->desktopNotifications()->showNotification(tr("Extension installed"), tr("Extension was successfully installed"));
}

View File

@ -0,0 +1,40 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 David Rosca <nowrep@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
* ============================================================ */
#pragma once
#include "qzcommon.h"
#include <QObject>
class KArchiveDirectory;
class OcsSupport : public QObject
{
Q_OBJECT
public:
explicit OcsSupport(QObject *parent = nullptr);
bool handleUrl(const QUrl &url);
static OcsSupport *instance();
private:
void installTheme(const KArchiveDirectory *directory);
void installExtension(const KArchiveDirectory *directory);
};

View File

@ -47,8 +47,7 @@ bool Plugins::Plugin::isRemovable() const
bool Plugins::Plugin::operator==(const Plugin &other) const
{
return type == other.type &&
pluginId == other.pluginId;
return type == other.type && pluginId == other.pluginId;
}
Plugins::Plugins(QObject* parent)
@ -131,6 +130,21 @@ void Plugins::removePlugin(Plugins::Plugin *plugin)
emit availablePluginsChanged();
}
bool Plugins::addPlugin(const QString &id)
{
Plugin plugin = loadPlugin(id);
if (plugin.type == Plugin::Invalid) {
return false;
}
if (plugin.pluginSpec.name.isEmpty()) {
qWarning() << "Invalid plugin spec of" << id << "plugin";
return false;
}
registerAvailablePlugin(plugin);
emit availablePluginsChanged();
return true;
}
void Plugins::loadSettings()
{
QStringList defaultAllowedPlugins = {

View File

@ -86,6 +86,8 @@ public:
void unloadPlugin(Plugin* plugin);
void removePlugin(Plugin *plugin);
bool addPlugin(const QString &id);
void shutdown();
// SpeedDial

View File

@ -42,6 +42,7 @@
#include "ui_jsprompt.h"
#include "passwordmanager.h"
#include "scripts.h"
#include "ocssupport.h"
#include <iostream>
@ -453,6 +454,10 @@ bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::Navigatio
}
}
if (url.scheme() == QL1S("ocs") && OcsSupport::instance()->handleUrl(url)) {
return false;
}
const bool result = QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
if (result) {