#include <QDebug> #include <QUrl> #include <QUrlQuery> #include <QTemporaryFile> #include <QMimeDatabase> #include <QNetworkReply> #include "../core/config.h" #include "../core/network.h" #include "../utility/file.h" #include "../utility/json.h" #include "../utility/package.h" #include "xdgurl.h" namespace Handlers { XdgUrl::XdgUrl(const QString &xdgUrl, Core::Config *config, Core::Network *network, QObject *parent) : QObject(parent), _xdgUrl(xdgUrl), _config(config), _network(network) { _metadata = _parse(); _destinations = _loadDestinations(); connect(_network, &Core::Network::finished, this, &XdgUrl::_downloaded); } QJsonObject XdgUrl::_parse() { QUrl url(_xdgUrl); QUrlQuery query(url); QJsonObject metadata; metadata["scheme"] = QString("xdg"); metadata["command"] = QString("download"); metadata["url"] = QString(""); metadata["type"] = QString("downloads"); metadata["filename"] = QString(""); if (!url.scheme().isEmpty()) { metadata["scheme"] = url.scheme(); } if (!url.host().isEmpty()) { metadata["command"] = url.host(); } if (query.hasQueryItem("url") && !query.queryItemValue("url").isEmpty()) { metadata["url"] = query.queryItemValue("url", QUrl::FullyDecoded); } if (query.hasQueryItem("type") && !query.queryItemValue("type").isEmpty()) { metadata["type"] = query.queryItemValue("type", QUrl::FullyDecoded); } if (query.hasQueryItem("filename") && !query.queryItemValue("filename").isEmpty()) { metadata["filename"] = QUrl(query.queryItemValue("filename", QUrl::FullyDecoded)).fileName(); } if (!metadata["url"].toString().isEmpty() && metadata["filename"].toString().isEmpty()) { metadata["filename"] = QUrl(metadata["url"].toString()).fileName(); } return metadata; } QString XdgUrl::_convertPathString(const QString &path) { QString newPath = path; if (newPath.contains("$HOME")) { newPath.replace("$HOME", Utility::File::homePath()); } else if (newPath.contains("$XDG_DATA")) { newPath.replace("$XDG_DATA", Utility::File::xdgDataHomePath()); } else if (newPath.contains("$KDE_DATA")) { newPath.replace("$KDE_DATA", Utility::File::kdeDataHomePath()); } return newPath; } QJsonObject XdgUrl::_loadDestinations() { QJsonObject destinations; QJsonObject configDestinations = _config->get("destinations"); QJsonObject configDestinationsAlias = _config->get("destinations_alias"); foreach (const QString key, configDestinations.keys()) { destinations[key] = _convertPathString(configDestinations[key].toString()); } foreach (const QString key, configDestinationsAlias.keys()) { QString value = configDestinationsAlias[key].toString(); if (destinations.contains(value)) { destinations[key] = destinations.value(value); } } return destinations; } void XdgUrl::_saveDownloadedFile(QNetworkReply *reply) { QJsonObject result; QTemporaryFile temporaryFile; if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) { result["error"] = QString("save_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } QMimeDatabase mimeDb; QString mimeType = mimeDb.mimeTypeForFile(temporaryFile.fileName()).name(); if (mimeType == "text/html" || mimeType == "application/xhtml+xml") { result["error"] = QString("filetype_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } QString type = _metadata["type"].toString(); QString destination = _destinations[type].toString(); QString path = destination + "/" + _metadata["filename"].toString(); Utility::File::makeDir(destination); Utility::File::remove(path); // Remove previous downloaded file if (!temporaryFile.copy(path)) { result["error"] = QString("save_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } result["success"] = QString("download_success"); result["destination"] = destination; result["path"] = path; emit finished(Utility::Json::convertObjToStr(result)); } void XdgUrl::_installDownloadedFile(QNetworkReply *reply) { QJsonObject result; QTemporaryFile temporaryFile; if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) { result["error"] = QString("save_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } QMimeDatabase mimeDb; QString mimeType = mimeDb.mimeTypeForFile(temporaryFile.fileName()).name(); if (mimeType == "text/html" || mimeType == "application/xhtml+xml") { result["error"] = QString("filetype_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } QString type = _metadata["type"].toString(); QString destination = _destinations[type].toString(); QString path = destination + "/" + _metadata["filename"].toString(); Utility::File::makeDir(destination); Utility::File::remove(path); // Remove previous downloaded file if ((type == "plasma_plasmoids" || type == "plasma4_plasmoids" || type == "plasma5_plasmoids") && Utility::Package::installPlasmapkg(temporaryFile.fileName(), "plasmoid")) { qInfo() << "The plasmoid has been installed"; } else if ((type == "plasma_look_and_feel" || type == "plasma5_look_and_feel") && Utility::Package::installPlasmapkg(temporaryFile.fileName(), "lookandfeel")) { qInfo() << "The plasma look and feel has been installed"; } else if ((type == "plasma_desktopthemes" || type == "plasma5_desktopthemes") && Utility::Package::installPlasmapkg(temporaryFile.fileName(), "theme")) { qInfo() << "The plasma desktop theme has been installed"; } else if (type == "kwin_effects" && Utility::Package::installPlasmapkg(temporaryFile.fileName(), "kwineffect")) { qInfo() << "The KWin effect has been installed"; } else if (type == "kwin_scripts" && Utility::Package::installPlasmapkg(temporaryFile.fileName(), "kwinscript")) { qInfo() << "The KWin script has been installed"; } else if (type == "kwin_tabbox" && Utility::Package::installPlasmapkg(temporaryFile.fileName(), "windowswitcher")) { qInfo() << "The KWin window switcher has been installed"; } else if (Utility::Package::uncompressArchive(temporaryFile.fileName(), destination)) { qInfo() << "The archive file has been uncompressed into" << destination; } else if (temporaryFile.copy(path)) { qInfo() << "Saved the file as" << path; } else { result["error"] = QString("install_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } result["success"] = QString("install_success"); result["destination"] = destination; result["path"] = path; emit finished(Utility::Json::convertObjToStr(result)); } /** * Private slots */ void XdgUrl::_downloaded(QNetworkReply *reply) { QJsonObject result; if (reply->error() != QNetworkReply::NoError) { result["error"] = QString("network_error"); emit finished(Utility::Json::convertObjToStr(result)); return; } // If the network reply has a refresh header, retry download if (reply->hasRawHeader("Refresh")) { QString refreshUrl = QString(reply->rawHeader("Refresh")).split("url=").last(); if (refreshUrl.startsWith("/")) { refreshUrl = reply->url().authority() + refreshUrl; } _network->get(QUrl(refreshUrl)); return; } if (_metadata["command"].toString() == "download") { _saveDownloadedFile(reply); } else if (_metadata["command"].toString() == "install") { _installDownloadedFile(reply); } } /** * Public slots */ QString XdgUrl::getXdgUrl() { return _xdgUrl; } QString XdgUrl::getMetadata() { return Utility::Json::convertObjToStr(_metadata); } bool XdgUrl::isValid() { QString scheme = _metadata["scheme"].toString(); QString command = _metadata["command"].toString(); QString url = _metadata["url"].toString(); QString type = _metadata["type"].toString(); QString filename = _metadata["filename"].toString(); if ((scheme == "xdg" || scheme == "xdgs") && (command == "download" || command == "install") && QUrl(url).isValid() && _destinations.contains(type) && !filename.isEmpty()) { return true; } return false; } void XdgUrl::process() { /** * xdgs scheme is a reserved name, so the process of xdgs * is the same process of the xdg scheme currently. */ if (isValid()) { _network->get(QUrl(_metadata["url"].toString())); } } } // namespace Handlers