Skip to content
Snippets Groups Projects
xdgurl.cpp 9.02 KiB
Newer Older
akiraohgaki's avatar
akiraohgaki committed
#include "xdgurl.h"

akiraohgaki's avatar
akiraohgaki committed
#include <QUrl>
#include <QUrlQuery>
akiraohgaki's avatar
akiraohgaki committed
#include <QTemporaryFile>
akiraohgaki's avatar
akiraohgaki committed
#include <QNetworkReply>
akiraohgaki's avatar
akiraohgaki committed
#include <QDesktopServices>
akiraohgaki's avatar
akiraohgaki committed

#include "../core/config.h"
#include "../core/network.h"
#include "../utility/file.h"
akiraohgaki's avatar
akiraohgaki committed
#include "../utility/package.h"
akiraohgaki's avatar
akiraohgaki committed

akiraohgaki's avatar
akiraohgaki committed
namespace handlers {
akiraohgaki's avatar
akiraohgaki committed

akiraohgaki's avatar
akiraohgaki committed
XdgUrl::XdgUrl(const QString &xdgUrl, core::Config *config, core::Network *network, QObject *parent) :
akiraohgaki's avatar
akiraohgaki committed
    QObject(parent), xdgUrl_(xdgUrl), config_(config), network_(network)
akiraohgaki's avatar
akiraohgaki committed
{
akiraohgaki's avatar
akiraohgaki committed
    parse_();
    loadDestinations_();
akiraohgaki's avatar
akiraohgaki committed
    connect(network_, &core::Network::finished, this, &XdgUrl::downloaded_);
    connect(network_, &core::Network::downloadProgress, this, &XdgUrl::downloadProgress);
akiraohgaki's avatar
akiraohgaki committed
}

akiraohgaki's avatar
akiraohgaki committed
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()) {
        QJsonObject result;
        result["status"] = QString("error_validation");
        result["message"] = QString("Invalid XDG-URL " + xdgUrl_);
        emit error(result);
        return;
    }

    network_->get(QUrl(metadata_["url"].toString()));
    emit started();
}

void XdgUrl::openDestination()
{
    if (!destination_.isEmpty()) {
        QDesktopServices::openUrl(QUrl("file://" + destination_));
    }
}

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;
}

QString XdgUrl::getXdgUrl()
{
    return xdgUrl_;
}

QJsonObject XdgUrl::getMetadata()
{
    return metadata_;
}

void XdgUrl::downloaded_(QNetworkReply *reply)
{
    if (reply->error() != QNetworkReply::NoError) {
        QJsonObject result;
        result["status"] = QString("error_network");
        result["message"] = reply->errorString();
        emit error(result);
        return;
    }

    if (reply->hasRawHeader("Location")) {
        QString redirectUrl = QString(reply->rawHeader("Location"));
        if (redirectUrl.startsWith("/")) {
            redirectUrl = reply->url().authority() + redirectUrl;
        }
        network_->get(QUrl(redirectUrl));
        return;
    }

    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);
    }
}

akiraohgaki's avatar
akiraohgaki committed
void XdgUrl::parse_()
akiraohgaki's avatar
akiraohgaki committed
{
akiraohgaki's avatar
akiraohgaki committed
    QUrl url(xdgUrl_);
akiraohgaki's avatar
akiraohgaki committed
    QUrlQuery query(url);

akiraohgaki's avatar
akiraohgaki committed
    metadata_["scheme"] = QString("xdg");
    metadata_["command"] = QString("download");
    metadata_["url"] = QString("");
    metadata_["type"] = QString("downloads");
    metadata_["filename"] = QString("");
akiraohgaki's avatar
akiraohgaki committed

    if (!url.scheme().isEmpty()) {
akiraohgaki's avatar
akiraohgaki committed
        metadata_["scheme"] = url.scheme();
akiraohgaki's avatar
akiraohgaki committed
    }

    if (!url.host().isEmpty()) {
akiraohgaki's avatar
akiraohgaki committed
        metadata_["command"] = url.host();
akiraohgaki's avatar
akiraohgaki committed
    }

    if (query.hasQueryItem("url") && !query.queryItemValue("url").isEmpty()) {
akiraohgaki's avatar
akiraohgaki committed
        metadata_["url"] = query.queryItemValue("url", QUrl::FullyDecoded);
akiraohgaki's avatar
akiraohgaki committed
    }

    if (query.hasQueryItem("type") && !query.queryItemValue("type").isEmpty()) {
akiraohgaki's avatar
akiraohgaki committed
        metadata_["type"] = query.queryItemValue("type", QUrl::FullyDecoded);
akiraohgaki's avatar
akiraohgaki committed
    }

    if (query.hasQueryItem("filename") && !query.queryItemValue("filename").isEmpty()) {
akiraohgaki's avatar
akiraohgaki committed
        metadata_["filename"] = QUrl(query.queryItemValue("filename", QUrl::FullyDecoded)).fileName();
akiraohgaki's avatar
akiraohgaki committed
    }

akiraohgaki's avatar
akiraohgaki committed
    if (!metadata_["url"].toString().isEmpty() && metadata_["filename"].toString().isEmpty()) {
        metadata_["filename"] = QUrl(metadata_["url"].toString()).fileName();
akiraohgaki's avatar
akiraohgaki committed
    }
akiraohgaki's avatar
akiraohgaki committed

akiraohgaki's avatar
akiraohgaki committed
void XdgUrl::loadDestinations_()
akiraohgaki's avatar
akiraohgaki committed
    QJsonObject configDestinations = config_->get("destinations");
    QJsonObject configDestinationsAlias = config_->get("destinations_alias");

    foreach (const QString key, configDestinations.keys()) {
akiraohgaki's avatar
akiraohgaki committed
        destinations_[key] = convertPathString_(configDestinations[key].toString());
    }

    foreach (const QString key, configDestinationsAlias.keys()) {
        QString value = configDestinationsAlias[key].toString();
akiraohgaki's avatar
akiraohgaki committed
        if (destinations_.contains(value)) {
            destinations_[key] = destinations_.value(value);
akiraohgaki's avatar
akiraohgaki committed
QString XdgUrl::convertPathString_(const QString &path)
akiraohgaki's avatar
akiraohgaki committed
{
    QString newPath = path;
akiraohgaki's avatar
akiraohgaki committed
    if (newPath.contains("$HOME")) {
akiraohgaki's avatar
akiraohgaki committed
        newPath.replace("$HOME", utility::File::homePath());
akiraohgaki's avatar
akiraohgaki committed
    }
akiraohgaki's avatar
akiraohgaki committed
    else if (newPath.contains("$XDG_DATA_HOME")) {
akiraohgaki's avatar
akiraohgaki committed
        newPath.replace("$XDG_DATA_HOME", utility::File::xdgDataHomePath());
akiraohgaki's avatar
akiraohgaki committed
    }
akiraohgaki's avatar
akiraohgaki committed
    else if (newPath.contains("$KDEHOME")) {
akiraohgaki's avatar
akiraohgaki committed
        newPath.replace("$KDEHOME", utility::File::kdehomePath());
akiraohgaki's avatar
akiraohgaki committed
    }
akiraohgaki's avatar
akiraohgaki committed
    return newPath;
}

akiraohgaki's avatar
akiraohgaki committed
void XdgUrl::saveDownloadedFile_(QNetworkReply *reply)
akiraohgaki's avatar
akiraohgaki committed
{
akiraohgaki's avatar
akiraohgaki committed
    QJsonObject result;

akiraohgaki's avatar
akiraohgaki committed
    QTemporaryFile temporaryFile;

akiraohgaki's avatar
akiraohgaki committed
    if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) {
akiraohgaki's avatar
akiraohgaki committed
        result["status"] = QString("error_save");
        result["message"] = temporaryFile.errorString();
akiraohgaki's avatar
akiraohgaki committed
        emit error(result);
akiraohgaki's avatar
akiraohgaki committed
        return;
    }

akiraohgaki's avatar
akiraohgaki committed
    QString type = metadata_["type"].toString();
    QString destination = destinations_[type].toString();
    QString path = destination + "/" + metadata_["filename"].toString();
akiraohgaki's avatar
akiraohgaki committed
    utility::File::makeDir(destination);
    utility::File::remove(path); // Remove previous downloaded file
akiraohgaki's avatar
akiraohgaki committed

    if (!temporaryFile.copy(path)) {
akiraohgaki's avatar
akiraohgaki committed
        result["status"] = QString("error_save");
        result["message"] = temporaryFile.errorString();
akiraohgaki's avatar
akiraohgaki committed
        emit error(result);
akiraohgaki's avatar
akiraohgaki committed
        return;
    }

akiraohgaki's avatar
akiraohgaki committed
    destination_ = destination;
akiraohgaki's avatar
akiraohgaki committed
    result["status"] = QString("success_download");
    result["message"] = QString("The file has been stored into " + destination);
akiraohgaki's avatar
akiraohgaki committed
    emit finished(result);
akiraohgaki's avatar
akiraohgaki committed
void XdgUrl::installDownloadedFile_(QNetworkReply *reply)
akiraohgaki's avatar
akiraohgaki committed
{
akiraohgaki's avatar
akiraohgaki committed
    QJsonObject result;

    QTemporaryFile temporaryFile;

    if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) {
akiraohgaki's avatar
akiraohgaki committed
        result["status"] = QString("error_save");
        result["message"] = temporaryFile.errorString();
akiraohgaki's avatar
akiraohgaki committed
        emit error(result);
akiraohgaki's avatar
akiraohgaki committed
    QString type = metadata_["type"].toString();
    QString destination = destinations_[type].toString();
    QString path = destination + "/" + metadata_["filename"].toString();
akiraohgaki's avatar
akiraohgaki committed
    utility::File::makeDir(destination);
    utility::File::remove(path); // Remove previous downloaded file
akiraohgaki's avatar
akiraohgaki committed
    if (type == "bin"
akiraohgaki's avatar
akiraohgaki committed
            && utility::Package::installProgram(temporaryFile.fileName(), path)) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The program has been installed into " + destination);
    }
    else if ((type == "plasma_plasmoids" || type == "plasma4_plasmoids" || type == "plasma5_plasmoids")
akiraohgaki's avatar
akiraohgaki committed
             && utility::Package::installPlasmapkg(temporaryFile.fileName(), "plasmoid")) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The plasmoid has been installed");
akiraohgaki's avatar
akiraohgaki committed
    }
    else if ((type == "plasma_look_and_feel" || type == "plasma5_look_and_feel")
akiraohgaki's avatar
akiraohgaki committed
             && utility::Package::installPlasmapkg(temporaryFile.fileName(), "lookandfeel")) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The plasma look and feel has been installed");
akiraohgaki's avatar
akiraohgaki committed
    }
    else if ((type == "plasma_desktopthemes" || type == "plasma5_desktopthemes")
akiraohgaki's avatar
akiraohgaki committed
             && utility::Package::installPlasmapkg(temporaryFile.fileName(), "theme")) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The plasma desktop theme has been installed");
akiraohgaki's avatar
akiraohgaki committed
    }
    else if (type == "kwin_effects"
akiraohgaki's avatar
akiraohgaki committed
             && utility::Package::installPlasmapkg(temporaryFile.fileName(), "kwineffect")) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The KWin effect has been installed");
akiraohgaki's avatar
akiraohgaki committed
    }
    else if (type == "kwin_scripts"
akiraohgaki's avatar
akiraohgaki committed
             && utility::Package::installPlasmapkg(temporaryFile.fileName(), "kwinscript")) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The KWin script has been installed");
akiraohgaki's avatar
akiraohgaki committed
    }
    else if (type == "kwin_tabbox"
akiraohgaki's avatar
akiraohgaki committed
             && utility::Package::installPlasmapkg(temporaryFile.fileName(), "windowswitcher")) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The KWin window switcher has been installed");
akiraohgaki's avatar
akiraohgaki committed
    else if (utility::Package::uncompressArchive(temporaryFile.fileName(), destination)) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The archive file has been uncompressed into " + destination);
akiraohgaki's avatar
akiraohgaki committed
    }
    else if (temporaryFile.copy(path)) {
akiraohgaki's avatar
akiraohgaki committed
        result["message"] = QString("The file has been stored into " + destination);
akiraohgaki's avatar
akiraohgaki committed
    }
    else {
akiraohgaki's avatar
akiraohgaki committed
        result["status"] = QString("error_install");
        result["message"] = temporaryFile.errorString();
akiraohgaki's avatar
akiraohgaki committed
        emit error(result);
akiraohgaki's avatar
akiraohgaki committed
    destination_ = destination;
akiraohgaki's avatar
akiraohgaki committed
    result["status"] = QString("success_install");
akiraohgaki's avatar
akiraohgaki committed
    emit finished(result);
akiraohgaki's avatar
akiraohgaki committed
} // namespace handlers