File indexing completed on 2023-09-24 04:14:57

0001 /*
0002     SPDX-FileCopyrightText: 2011 Aaron Seigo <aseigo@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "packagestructure.h"
0008 #include "debug_p.h"
0009 #include "private/package_p.h"
0010 #include "private/packagestructure_p.h"
0011 #include <QDebug>
0012 
0013 #include <kpackage/packageloader.h>
0014 #include <kpackage/packagestructure.h>
0015 
0016 #include <QVariantMap>
0017 
0018 #include <KDesktopFile>
0019 #include <KJob>
0020 #include <QDBusConnection>
0021 #include <QDBusPendingCall>
0022 #include <QDir>
0023 #include <QFile>
0024 
0025 namespace Plasma
0026 {
0027 QHash<KPackage::Package *, Plasma::Package *> PackageStructureWrapper::s_packagesMap;
0028 
0029 PackageStructureWrapper::PackageStructureWrapper(Plasma::PackageStructure *structure, QObject *parent, const QVariantList &args)
0030     : KPackage::PackageStructure(parent, args)
0031     , m_struct(structure)
0032 {
0033 }
0034 
0035 PackageStructureWrapper::~PackageStructureWrapper()
0036 {
0037 }
0038 
0039 void PackageStructureWrapper::initPackage(KPackage::Package *package)
0040 {
0041     if (!m_struct || !s_packagesMap.contains(package)) {
0042         return;
0043     }
0044 
0045     m_struct->initPackage(s_packagesMap.value(package));
0046 }
0047 
0048 void PackageStructureWrapper::pathChanged(KPackage::Package *package)
0049 {
0050     if (!m_struct || !s_packagesMap.contains(package)) {
0051         return;
0052     }
0053 
0054     m_struct->pathChanged(s_packagesMap.value(package));
0055 }
0056 
0057 KJob *PackageStructureWrapper::install(KPackage::Package *package, const QString &archivePath, const QString &packageRoot)
0058 {
0059     if (!m_struct || !s_packagesMap.contains(package)) {
0060         return nullptr;
0061     }
0062 
0063     return m_struct->install(s_packagesMap.value(package), archivePath, packageRoot);
0064 }
0065 
0066 KJob *PackageStructureWrapper::uninstall(KPackage::Package *package, const QString &packageRoot)
0067 {
0068     if (!m_struct || !s_packagesMap.contains(package)) {
0069         return nullptr;
0070     }
0071 
0072     return m_struct->uninstall(s_packagesMap.value(package), packageRoot);
0073 }
0074 
0075 void PackageStructurePrivate::installPathChanged(const QString &path)
0076 {
0077     KJob *job = qobject_cast<KJob *>(q->sender());
0078     if (!job || job->error()) {
0079         return;
0080     }
0081 
0082     const QString servicePrefix = job->property("servicePrefix").toString();
0083     const QString serviceName = job->property("serviceName").toString();
0084 
0085     // uninstall
0086     if (path.isEmpty()) {
0087         if (serviceName.isEmpty()) {
0088             return;
0089         }
0090 
0091         QString service = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + serviceName;
0092 
0093         bool ok = QFile::remove(service);
0094         if (!ok) {
0095             qCWarning(LOG_PLASMA) << "Unable to remove " << service;
0096         }
0097 
0098         // install
0099     } else {
0100         if (!servicePrefix.isEmpty()) {
0101             // and now we register it as a service =)
0102             QString metaPath = path + QStringLiteral("/metadata.desktop");
0103             KDesktopFile df(metaPath);
0104             KConfigGroup cg = df.desktopGroup();
0105             const QString pluginName = cg.readEntry("X-KDE-PluginInfo-Name", QString());
0106 
0107             if (pluginName.isEmpty()) {
0108                 return;
0109             }
0110 
0111             // Q: should not installing it as a service disqualify it?
0112             // Q: i don't think so since KServiceTypeTrader may not be
0113             // used by the installing app in any case, and the
0114             // package is properly installed - aseigo
0115 
0116             // TODO: remove installation of the desktop file in kservices5 when possible
0117 
0118             const QString serviceName = servicePrefix + pluginName + QStringLiteral(".desktop");
0119 
0120             QString localServiceDirectory = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/");
0121             if (!QDir().mkpath(localServiceDirectory)) {
0122                 qCDebug(LOG_PLASMA) << "Failed to create ... " << localServiceDirectory;
0123                 qCWarning(LOG_PLASMA) << "Could not create local service directory:" << localServiceDirectory;
0124                 return;
0125             }
0126             QString service = localServiceDirectory + serviceName;
0127 
0128             qCDebug(LOG_PLASMA) << "-- Copying " << metaPath << service;
0129             const bool ok = QFile::copy(metaPath, service);
0130             if (ok) {
0131                 qCDebug(LOG_PLASMA) << "Copying metadata went ok.";
0132                 // the icon in the installed file needs to point to the icon in the
0133                 // installation dir!
0134                 QString iconPath = path + QLatin1Char('/') + cg.readEntry("Icon");
0135                 QFile icon(iconPath);
0136                 if (icon.exists()) {
0137                     KDesktopFile df(service);
0138                     KConfigGroup cg = df.desktopGroup();
0139                     cg.writeEntry("Icon", iconPath);
0140                 }
0141             } else {
0142                 qCWarning(LOG_PLASMA) << "Could not register package as service (this is not necessarily fatal):" << serviceName;
0143             }
0144         }
0145     }
0146     const auto call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded5"),
0147                                                      QStringLiteral("/kbuildsycoca"),
0148                                                      QStringLiteral("org.kde.kbuildsycoca"),
0149                                                      QStringLiteral("recreate"));
0150     QDBusConnection::sessionBus().asyncCall(call);
0151 }
0152 
0153 PackageStructure::PackageStructure(QObject *parent, const QVariantList &args)
0154     : QObject(parent)
0155     , d(new PackageStructurePrivate(this))
0156 {
0157     if (!args.isEmpty() && args.first().canConvert<QString>()) {
0158         d->internalStructure = KPackage::PackageLoader::self()->loadPackageStructure(args.first().toString());
0159     }
0160 
0161     Q_UNUSED(args)
0162 }
0163 
0164 PackageStructure::~PackageStructure()
0165 {
0166     delete d;
0167 }
0168 
0169 void PackageStructure::initPackage(Package *package)
0170 {
0171     if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
0172         d->internalStructure->initPackage(package->d->internalPackage);
0173     }
0174 }
0175 
0176 void PackageStructure::pathChanged(Package *package)
0177 {
0178     if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
0179         d->internalStructure->pathChanged(package->d->internalPackage);
0180     }
0181 }
0182 
0183 KJob *PackageStructure::install(Package *package, const QString &archivePath, const QString &packageRoot)
0184 {
0185     if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
0186         KJob *job = d->internalStructure->install(package->d->internalPackage, archivePath, packageRoot);
0187         if (job) {
0188             job->setProperty("servicePrefix", package->servicePrefix());
0189             connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
0190         }
0191         return job;
0192     } else if (d->internalStructure) {
0193         KJob *job = d->internalStructure->KPackage::PackageStructure::install(package->d->internalPackage, archivePath, packageRoot);
0194         connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
0195         return job;
0196     }
0197 
0198     return nullptr;
0199 }
0200 
0201 KJob *PackageStructure::uninstall(Package *package, const QString &packageRoot)
0202 {
0203     if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
0204         QString metaPath = package->path() + QStringLiteral("/metadata.desktop");
0205         KDesktopFile df(metaPath);
0206         KConfigGroup cg = df.desktopGroup();
0207         const QString pluginName = cg.readEntry("X-KDE-PluginInfo-Name", QString());
0208         const QString serviceName = package->servicePrefix() + pluginName + QStringLiteral(".desktop");
0209 
0210         KJob *job = d->internalStructure->uninstall(package->d->internalPackage, packageRoot);
0211         if (job) {
0212             job->setProperty("serviceName", serviceName);
0213 
0214             connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
0215         }
0216         return job;
0217     } else if (d->internalStructure) {
0218         KJob *job = d->internalStructure->KPackage::PackageStructure::uninstall(package->d->internalPackage, packageRoot);
0219         connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
0220         return job;
0221     }
0222 
0223     return nullptr;
0224 }
0225 
0226 }
0227 
0228 #include "moc_packagestructure.cpp"
0229 #include "private/moc_packagestructure_p.cpp"