Warning, file /network/falkon/src/lib/plugins/ocssupport.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2019 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "ocssupport.h" 0019 #include "pluginproxy.h" 0020 #include "datapaths.h" 0021 #include "networkmanager.h" 0022 #include "desktopfile.h" 0023 #include "desktopnotificationsfactory.h" 0024 #include "mainapplication.h" 0025 0026 #include <QDir> 0027 #include <QBuffer> 0028 #include <QUrlQuery> 0029 #include <QNetworkReply> 0030 0031 #include <KZip> 0032 0033 Q_GLOBAL_STATIC(OcsSupport, qz_ocs_support) 0034 0035 static DesktopFile readMetaData(const KArchiveDirectory *directory) 0036 { 0037 const KArchiveEntry *entry = directory->entry(QSL("metadata.desktop")); 0038 if (!entry || !entry->isFile()) { 0039 qWarning() << "No metadata.desktop found"; 0040 return {}; 0041 } 0042 const QString tempDir = DataPaths::path(DataPaths::Temp); 0043 static_cast<const KArchiveFile*>(entry)->copyTo(tempDir); 0044 return DesktopFile(tempDir + QL1S("/metadata.desktop")); 0045 } 0046 0047 OcsSupport::OcsSupport(QObject *parent) 0048 : QObject(parent) 0049 { 0050 } 0051 0052 bool OcsSupport::handleUrl(const QUrl &url) 0053 { 0054 if (url.host() != QL1S("install")) { 0055 return false; 0056 } 0057 0058 QUrl fileUrl; 0059 QString fileType; 0060 QString fileName; 0061 0062 const auto items = QUrlQuery(url).queryItems(QUrl::FullyDecoded); 0063 for (const auto &item : items) { 0064 if (item.first == QL1S("url")) { 0065 fileUrl = QUrl(item.second); 0066 } else if (item.first == QL1S("type")) { 0067 fileType = item.second; 0068 } else if (item.first == QL1S("filename")) { 0069 fileName = item.second; 0070 } 0071 } 0072 0073 if (!fileType.startsWith(QL1S("falkon_"))) { 0074 return false; 0075 } 0076 0077 if (fileType != QL1S("falkon_themes") && fileType != QL1S("falkon_extensions")) { 0078 qWarning() << "Unsupported type" << fileType; 0079 return false; 0080 } 0081 0082 if (!fileUrl.isValid()) { 0083 qWarning() << "Invalid url" << fileUrl << url; 0084 return false; 0085 } 0086 0087 qInfo() << "Downloading" << fileUrl; 0088 0089 QNetworkReply *reply = mApp->networkManager()->get(QNetworkRequest(fileUrl)); 0090 connect(reply, &QNetworkReply::finished, this, [=]() { 0091 reply->deleteLater(); 0092 if (reply->error() != QNetworkReply::NoError) { 0093 qWarning() << "Error downloading" << fileUrl << reply->error() << reply->errorString(); 0094 return; 0095 } 0096 QBuffer buf; 0097 buf.setData(reply->readAll()); 0098 KZip zip(&buf); 0099 if (!zip.open(QIODevice::ReadOnly)) { 0100 qWarning() << "Failed to open archive"; 0101 return; 0102 } 0103 QString notifyMessage; 0104 if (fileType == QL1S("falkon_themes")) { 0105 installTheme(zip.directory()); 0106 } else if (fileType == QL1S("falkon_extensions")) { 0107 installExtension(zip.directory()); 0108 } 0109 }); 0110 0111 return true; 0112 } 0113 0114 // static 0115 OcsSupport *OcsSupport::instance() 0116 { 0117 return qz_ocs_support(); 0118 } 0119 0120 void OcsSupport::installTheme(const KArchiveDirectory *directory) 0121 { 0122 auto showError = []() { 0123 mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Failed to install theme")); 0124 }; 0125 0126 if (directory->entries().size() != 1) { 0127 qWarning() << "Invalid archive format"; 0128 showError(); 0129 return; 0130 } 0131 0132 const QString name = directory->entries().at(0); 0133 const KArchiveEntry *entry = directory->entry(name); 0134 if (!entry || !entry->isDirectory()) { 0135 qWarning() << "Invalid archive format"; 0136 showError(); 0137 return; 0138 } 0139 0140 const DesktopFile metaData = readMetaData(static_cast<const KArchiveDirectory*>(entry)); 0141 0142 const QString targetDir = DataPaths::path(DataPaths::Config) + QL1S("/themes"); 0143 QDir().mkpath(targetDir); 0144 0145 if (QFileInfo::exists(targetDir + QL1C('/') + name)) { 0146 qWarning() << "Theme" << name << "already exists"; 0147 mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Theme is already installed")); 0148 return; 0149 } 0150 0151 if (!directory->copyTo(targetDir)) { 0152 qWarning() << "Failed to copy theme to" << targetDir; 0153 showError(); 0154 return; 0155 } 0156 0157 qInfo() << "Theme installed to" << targetDir; 0158 0159 mApp->desktopNotifications()->showNotification(tr("Theme installed"), tr("'%1' was successfully installed").arg(metaData.name())); 0160 } 0161 0162 void OcsSupport::installExtension(const KArchiveDirectory *directory) 0163 { 0164 auto showError = []() { 0165 mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Failed to install extension")); 0166 }; 0167 0168 if (directory->entries().size() != 1) { 0169 qWarning() << "Invalid archive format"; 0170 showError(); 0171 return; 0172 } 0173 0174 const QString name = directory->entries().at(0); 0175 const KArchiveEntry *entry = directory->entry(name); 0176 if (!entry || !entry->isDirectory()) { 0177 qWarning() << "Invalid archive format"; 0178 showError(); 0179 return; 0180 } 0181 0182 const DesktopFile metaData = readMetaData(static_cast<const KArchiveDirectory*>(entry)); 0183 const QString extensionType = metaData.value(QSL("X-Falkon-Type")).toString(); 0184 0185 QString type; 0186 if (extensionType == QL1S("Extension/Python")) { 0187 type = QSL("python"); 0188 } else if (extensionType == QL1S("Extension/Qml")) { 0189 type = QSL("qml"); 0190 } 0191 0192 if (type.isEmpty()) { 0193 qWarning() << "Unsupported extension type" << extensionType; 0194 showError(); 0195 return; 0196 } 0197 0198 const QString targetDir = DataPaths::path(DataPaths::Config) + QL1S("/plugins/"); 0199 QDir().mkpath(targetDir); 0200 0201 if (QFileInfo::exists(targetDir + QL1S("/") + name)) { 0202 qWarning() << "Extension" << name << "already exists"; 0203 mApp->desktopNotifications()->showNotification(tr("Installation failed"), tr("Extension is already installed")); 0204 return; 0205 } 0206 0207 if (!directory->copyTo(targetDir)) { 0208 qWarning() << "Failed to copy extension to" << targetDir; 0209 showError(); 0210 return; 0211 } 0212 0213 qInfo() << "Extension installed to" << targetDir; 0214 0215 const QString fullId = QSL("%1:%2/%3").arg(type, targetDir, name); 0216 if (!mApp->plugins()->addPlugin(fullId)) { 0217 qWarning() << "Failed to add plugin" << fullId; 0218 showError(); 0219 return; 0220 } 0221 0222 mApp->desktopNotifications()->showNotification(tr("Extension installed"), tr("'%1' was successfully installed").arg(metaData.name())); 0223 }