Skip to content
Snippets Groups Projects
xdgurl.cpp 9.04 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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
    
    #include "xdgurl.h"
    
    namespace Handlers {
    
    
    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::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")) {
            newPath.replace("$HOME", Utility::File::homePath());
        }
    
    akiraohgaki's avatar
    akiraohgaki committed
        else if (newPath.contains("$XDG_DATA_HOME")) {
            newPath.replace("$XDG_DATA_HOME", Utility::File::xdgDataHomePath());
    
    akiraohgaki's avatar
    akiraohgaki committed
        }
    
    akiraohgaki's avatar
    akiraohgaki committed
        else if (newPath.contains("$KDEHOME")) {
            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
    
        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)) {
            result["message"] = QString("The program has been installed into " + destination);
        }
        else if ((type == "plasma_plasmoids" || type == "plasma4_plasmoids" || type == "plasma5_plasmoids")
                 && 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")
                 && 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")
                 && 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"
                 && 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"
                 && 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"
                 && 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
    /**
    
    akiraohgaki's avatar
    akiraohgaki committed
     * Slots
    
    akiraohgaki's avatar
    akiraohgaki committed
     */
    
    
    akiraohgaki's avatar
    akiraohgaki committed
    void XdgUrl::process()
    
    akiraohgaki's avatar
    akiraohgaki committed
    {
    
    akiraohgaki's avatar
    akiraohgaki committed
        /**
         * xdgs scheme is a reserved name, so the process of xdgs
         * is the same process of the xdg scheme currently.
         */
    
        if (!isValid()) {
    
    akiraohgaki's avatar
    akiraohgaki committed
            QJsonObject result;
    
    akiraohgaki's avatar
    akiraohgaki committed
            result["status"] = QString("error_validation");
    
    akiraohgaki's avatar
    akiraohgaki committed
            result["message"] = QString("Invalid XDG-URL " + xdgUrl_);
    
    akiraohgaki's avatar
    akiraohgaki committed
            emit error(result);
    
    akiraohgaki's avatar
    akiraohgaki committed
            return;
        }
    
    
    akiraohgaki's avatar
    akiraohgaki committed
        network_->get(QUrl(metadata_["url"].toString()));
    
    akiraohgaki's avatar
    akiraohgaki committed
        emit started();
    
    akiraohgaki's avatar
    akiraohgaki committed
    void XdgUrl::openDestination()
    
    akiraohgaki's avatar
    akiraohgaki committed
    {
    
    akiraohgaki's avatar
    akiraohgaki committed
        if (!destination_.isEmpty()) {
            QDesktopServices::openUrl(QUrl("file://" + destination_));
    
    akiraohgaki's avatar
    akiraohgaki committed
        }
    
    akiraohgaki's avatar
    akiraohgaki committed
    }
    
    
    akiraohgaki's avatar
    akiraohgaki committed
    bool XdgUrl::isValid()
    {
    
    akiraohgaki's avatar
    akiraohgaki committed
        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();
    
    akiraohgaki's avatar
    akiraohgaki committed
        if ((scheme == "xdg" || scheme == "xdgs")
                && (command == "download" || command == "install")
                && QUrl(url).isValid()
    
    akiraohgaki's avatar
    akiraohgaki committed
                && destinations_.contains(type)
    
    akiraohgaki's avatar
    akiraohgaki committed
                && !filename.isEmpty()) {
            return true;
    
    akiraohgaki's avatar
    akiraohgaki committed
        return false;
    
    akiraohgaki's avatar
    akiraohgaki committed
    QString XdgUrl::getXdgUrl()
    
    akiraohgaki's avatar
    akiraohgaki committed
    {
    
    akiraohgaki's avatar
    akiraohgaki committed
        return xdgUrl_;
    
    akiraohgaki's avatar
    akiraohgaki committed
    }
    
    akiraohgaki's avatar
    akiraohgaki committed
    
    
    akiraohgaki's avatar
    akiraohgaki committed
    QJsonObject XdgUrl::getMetadata()
    
    akiraohgaki's avatar
    akiraohgaki committed
    {
    
    akiraohgaki's avatar
    akiraohgaki committed
        return metadata_;
    
    akiraohgaki's avatar
    akiraohgaki committed
    }
    
    
    akiraohgaki's avatar
    akiraohgaki committed
    void XdgUrl::downloaded_(QNetworkReply *reply)
    
    akiraohgaki's avatar
    akiraohgaki committed
    {
        if (reply->error() != QNetworkReply::NoError) {
    
    akiraohgaki's avatar
    akiraohgaki committed
            QJsonObject result;
    
    akiraohgaki's avatar
    akiraohgaki committed
            result["status"] = QString("error_network");
            result["message"] = reply->errorString();
    
    akiraohgaki's avatar
    akiraohgaki committed
            emit error(result);
    
    akiraohgaki's avatar
    akiraohgaki committed
            return;
    
    akiraohgaki's avatar
    akiraohgaki committed
        }
    
    akiraohgaki's avatar
    akiraohgaki committed
    
    
    akiraohgaki's avatar
    akiraohgaki committed
        if (reply->hasRawHeader("Location")) {
            QString redirectUrl = QString(reply->rawHeader("Location"));
            if (redirectUrl.startsWith("/")) {
                redirectUrl = reply->url().authority() + redirectUrl;
            }
    
    akiraohgaki's avatar
    akiraohgaki committed
            network_->get(QUrl(redirectUrl));
    
    akiraohgaki's avatar
    akiraohgaki committed
            return;
        }
    
    akiraohgaki's avatar
    akiraohgaki committed
    
    
    akiraohgaki's avatar
    akiraohgaki committed
        if (reply->hasRawHeader("Refresh")) {
            QString refreshUrl = QString(reply->rawHeader("Refresh")).split("url=").last();
            if (refreshUrl.startsWith("/")) {
                refreshUrl = reply->url().authority() + refreshUrl;
            }
    
    akiraohgaki's avatar
    akiraohgaki committed
            network_->get(QUrl(refreshUrl));
    
    akiraohgaki's avatar
    akiraohgaki committed
            return;
        }
    
    
    akiraohgaki's avatar
    akiraohgaki committed
        if (metadata_["command"].toString() == "download") {
            saveDownloadedFile_(reply);
    
    akiraohgaki's avatar
    akiraohgaki committed
        }
    
    akiraohgaki's avatar
    akiraohgaki committed
        else if (metadata_["command"].toString() == "install") {
            installDownloadedFile_(reply);
    
    akiraohgaki's avatar
    akiraohgaki committed
    } // namespace Handlers