File indexing completed on 2024-05-05 12:10:10
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2016 Aleix Pol Gonzalez <aleixpol@kde.org> 0004 SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include <QCoreApplication> 0010 #include <QDebug> 0011 #include <QFile> 0012 #include <QFileInfo> 0013 #include <QStandardPaths> 0014 #include <QTimer> 0015 #include <QUrl> 0016 #include <QUrlQuery> 0017 0018 #include <KLocalizedString> 0019 0020 #include <KNotification> 0021 0022 #include <KNSCore/Engine> 0023 #include <KNSCore/QuestionManager> 0024 0025 #include "knshandlerversion.h" 0026 0027 /** 0028 * Unfortunately there are two knsrc files for the window decorations, but only one is used in the KCM. 0029 * But both are used by third parties, consequently we can not remove one. To solve this we create a symlink 0030 * which links the old cache file to the new cache file, which is exposed on the GUI. 0031 * This way users can again remove window decorations that are installed as a dependency of a global theme. 0032 * BUG: 414570 0033 */ 0034 void createSymlinkForWindowDecorations() 0035 { 0036 QFileInfo info(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/knewstuff3/aurorae.knsregistry")); 0037 // If we have created the symbolic link already we can exit the function here 0038 if (info.isSymbolicLink()) { 0039 return; 0040 } 0041 // Delete this file, it the KNS entries are not exposed in any GUI 0042 if (info.exists()) { 0043 QFile::remove(info.absoluteFilePath()); 0044 } 0045 QFileInfo newFileInfo(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/knewstuff3/window-decorations.knsregistry")); 0046 QFile file(newFileInfo.absoluteFilePath()); 0047 // Make sure that the file exists 0048 if (!newFileInfo.exists()) { 0049 file.open(QFile::WriteOnly); 0050 file.close(); 0051 } 0052 file.link(info.absoluteFilePath()); 0053 } 0054 0055 int main(int argc, char **argv) 0056 { 0057 createSymlinkForWindowDecorations(); 0058 QCoreApplication app(argc, argv); 0059 app.setApplicationName(QStringLiteral("kpackage-knshandler")); 0060 app.setApplicationVersion(knshandlerversion); 0061 app.setQuitLockEnabled(false); 0062 Q_ASSERT(app.arguments().count() == 2); 0063 0064 #ifdef TEST 0065 QStandardPaths::setTestModeEnabled(true); 0066 #endif 0067 0068 const QUrl url(app.arguments().last()); 0069 Q_ASSERT(url.isValid()); 0070 Q_ASSERT(url.scheme() == QLatin1String("kns")); 0071 0072 QString knsname; 0073 const QStringList availableConfigFiles = KNSCore::Engine::availableConfigFiles(); 0074 auto knsNameIt = std::find_if(availableConfigFiles.begin(), availableConfigFiles.end(), [&url](const QString &availableFile) { 0075 return availableFile.endsWith(QLatin1String("/") + url.host()); 0076 }); 0077 0078 if (knsNameIt == availableConfigFiles.end()) { 0079 qWarning() << "couldn't find knsrc file for" << url.host(); 0080 return 1; 0081 } else { 0082 knsname = *knsNameIt; 0083 } 0084 0085 const auto pathParts = url.path().split(QLatin1Char('/'), Qt::SkipEmptyParts); 0086 if (pathParts.size() != 2) { 0087 qWarning() << "wrong format in the url path" << url << pathParts; 0088 return 1; 0089 } 0090 const auto providerid = pathParts.at(0); 0091 const auto entryid = pathParts.at(1); 0092 int linkid = 1; 0093 if (url.hasQuery()) { 0094 QUrlQuery query(url); 0095 if (query.hasQueryItem(QStringLiteral("linkid"))) { 0096 bool ok; 0097 linkid = query.queryItemValue(QStringLiteral("linkid")).toInt(&ok); 0098 if (!ok) { 0099 qWarning() << "linkid is not an integer" << url << pathParts; 0100 return 1; 0101 } 0102 } 0103 } 0104 0105 KNSCore::Engine engine; 0106 int installedCount = 0; 0107 QObject::connect(KNSCore::QuestionManager::instance(), &KNSCore::QuestionManager::askQuestion, &engine, [](KNSCore::Question *question) { 0108 auto discardQuestion = [question]() { 0109 question->setResponse(KNSCore::Question::InvalidResponse); 0110 }; 0111 switch (question->questionType()) { 0112 case KNSCore::Question::YesNoQuestion: { 0113 auto f = KNotification::event(KNotification::StandardEvent::Notification, question->title(), question->question()); 0114 f->setActions({i18n("Yes"), i18n("No")}); 0115 QObject::connect(f, &KNotification::action1Activated, question, [question]() { 0116 question->setResponse(KNSCore::Question::YesResponse); 0117 }); 0118 QObject::connect(f, &KNotification::action2Activated, question, [question]() { 0119 question->setResponse(KNSCore::Question::NoResponse); 0120 }); 0121 QObject::connect(f, &KNotification::closed, question, discardQuestion); 0122 } break; 0123 case KNSCore::Question::ContinueCancelQuestion: { 0124 auto f = KNotification::event(KNotification::StandardEvent::Notification, question->title(), question->question()); 0125 f->setActions({i18n("Continue"), i18n("Cancel")}); 0126 QObject::connect(f, &KNotification::action1Activated, question, [question]() { 0127 question->setResponse(KNSCore::Question::ContinueResponse); 0128 }); 0129 QObject::connect(f, &KNotification::action2Activated, question, [question]() { 0130 question->setResponse(KNSCore::Question::CancelResponse); 0131 }); 0132 QObject::connect(f, &KNotification::closed, question, discardQuestion); 0133 } break; 0134 case KNSCore::Question::InputTextQuestion: 0135 case KNSCore::Question::SelectFromListQuestion: 0136 case KNSCore::Question::PasswordQuestion: 0137 discardQuestion(); 0138 break; 0139 } 0140 }); 0141 0142 QObject::connect(&engine, &KNSCore::Engine::signalProvidersLoaded, &engine, [&engine, entryid]() { 0143 engine.fetchEntryById(entryid); 0144 }); 0145 0146 QObject::connect(&engine, &KNSCore::Engine::signalErrorCode, &engine, [](KNSCore::ErrorCode errorCode, const QString &message, const QVariant &metadata) { 0147 qWarning() << "kns error:" << errorCode << message << metadata; 0148 QCoreApplication::exit(1); 0149 }); 0150 QObject::connect(&engine, 0151 &KNSCore::Engine::signalEntryEvent, 0152 &engine, 0153 [providerid, linkid, &engine, &installedCount](const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event) { 0154 if (event == KNSCore::EntryInternal::DetailsLoadedEvent) { 0155 // qDebug() << "checking..." << entry.status() << entry.providerId(); 0156 if (providerid != QUrl(entry.providerId()).host()) { 0157 qWarning() << "Wrong provider" << providerid << "instead of" << QUrl(entry.providerId()).host(); 0158 QCoreApplication::exit(1); 0159 } else if (entry.status() == KNS3::Entry::Downloadable) { 0160 qDebug() << "installing..."; 0161 installedCount++; 0162 engine.install(entry, linkid); 0163 } else if (installedCount == 0) { 0164 qDebug() << "already installed."; 0165 QCoreApplication::exit(0); 0166 } 0167 } else if (event == KNSCore::EntryInternal::StatusChangedEvent) { 0168 if (entry.status() == KNS3::Entry::Installed) { 0169 installedCount--; 0170 } 0171 if (installedCount == 0) { 0172 QCoreApplication::exit(0); 0173 } 0174 } 0175 }); 0176 if (!engine.init(knsname)) { 0177 qWarning() << "couldn't initialize" << knsname; 0178 return 1; 0179 } 0180 return app.exec(); 0181 }