File indexing completed on 2024-04-21 04:57:26

0001 /*
0002  *   SPDX-FileCopyrightText: 2012-2016 Ivan Cukic <ivan.cukic@kde.org>
0003  *   SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0004  *
0005  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006  */
0007 
0008 #include "KioActivities.h"
0009 #include "KioActivitiesApi.h"
0010 
0011 #include <QCoreApplication>
0012 
0013 #include <QByteArray>
0014 #include <QDebug>
0015 #include <QDir>
0016 #include <QFile>
0017 #include <QSqlDatabase>
0018 #include <QSqlDriver>
0019 #include <QSqlError>
0020 #include <QSqlField>
0021 #include <QSqlQuery>
0022 #include <QStandardPaths>
0023 
0024 #include <KIO/Job>
0025 #include <KLocalizedString>
0026 #include <KUser>
0027 
0028 #include <common/database/Database.h>
0029 #include <utils/d_ptr_implementation.h>
0030 #include <utils/qsqlquery_iterator.h>
0031 
0032 #include <PlasmaActivities/Consumer>
0033 #include <PlasmaActivities/Info>
0034 
0035 #include "KioActivitiesApi.h"
0036 #include <QProcess>
0037 
0038 // Pseudo plugin class to embed meta data
0039 class KIOPluginForMetaData : public QObject
0040 {
0041     Q_OBJECT
0042     Q_PLUGIN_METADATA(IID "org.kde.kio.slave.activities" FILE "activities.json")
0043 };
0044 
0045 extern "C" int Q_DECL_EXPORT kdemain(int argc, char **argv)
0046 {
0047     // necessary to use other kio slaves
0048     QCoreApplication app(argc, argv);
0049     if (argc != 4) {
0050         fprintf(stderr, "Usage: kio_activities protocol domain-socket1 domain-socket2\n");
0051         exit(-1);
0052     }
0053     // start the slave
0054     ActivitiesProtocol slave(argv[2], argv[3]);
0055     slave.dispatchLoop();
0056     return 0;
0057 }
0058 
0059 ActivitiesProtocol::ActivitiesProtocol(const QByteArray &poolSocket, const QByteArray &appSocket)
0060     : KIO::ForwardingWorkerBase("activities", poolSocket, appSocket)
0061 {
0062 }
0063 
0064 ActivitiesProtocol::~ActivitiesProtocol() = default;
0065 
0066 bool ActivitiesProtocol::rewriteUrl(const QUrl &url, QUrl &newUrl)
0067 {
0068     QString activity, path;
0069     switch (d->pathType(url, &activity, &path)) {
0070     case ActivitiesProtocolApi::RootItem:
0071     case ActivitiesProtocolApi::ActivityRootItem:
0072         if (activity == "current") {
0073             KActivities::Consumer activities;
0074             d->syncActivities(activities);
0075             newUrl = QUrl(QStringLiteral("activities:/") + activities.currentActivity());
0076             return true;
0077         }
0078         return false;
0079 
0080     case ActivitiesProtocolApi::ActivityPathItem: {
0081         // auto demangled = d->demangledPath(path);
0082         // QProcess::execute("kdialog",
0083         //                   { "--passivepopup",
0084         //                     path.midRef(1).toString() + "\n" + demangled });
0085 
0086         newUrl = QUrl::fromLocalFile(path);
0087         return true;
0088     }
0089 
0090     default:
0091         return true;
0092     }
0093 }
0094 
0095 KIO::WorkerResult ActivitiesProtocol::listDir(const QUrl &url)
0096 {
0097     KActivities::Consumer activities;
0098     d->syncActivities(activities);
0099 
0100     QString activity, path;
0101     switch (d->pathType(url, &activity, &path)) {
0102     case ActivitiesProtocolApi::RootItem: {
0103         KIO::UDSEntryList udslist;
0104 
0105         KIO::UDSEntry uds;
0106         uds.reserve(9);
0107         uds.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("current"));
0108         uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Current activity"));
0109         uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_TYPE, i18n("Activity"));
0110         uds.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("activities"));
0111         uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0112         uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0113         uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0500);
0114         uds.fastInsert(KIO::UDSEntry::UDS_USER, KUser().loginName());
0115         uds.fastInsert(KIO::UDSEntry::UDS_TARGET_URL, QStringLiteral("activities:/") + activities.currentActivity());
0116         udslist << uds;
0117 
0118         for (const auto &activity : activities.activities()) {
0119             udslist << d->activityEntry(activity);
0120         }
0121 
0122         listEntries(udslist);
0123         return KIO::WorkerResult::pass();
0124     }
0125 
0126     case ActivitiesProtocolApi::ActivityRootItem: {
0127         KIO::UDSEntryList udslist;
0128 
0129         auto database = Common::Database::instance(Common::Database::ResourcesDatabase, Common::Database::ReadOnly);
0130 
0131         if (!database) {
0132             return KIO::WorkerResult::pass();
0133         }
0134 
0135         if (activity == "current") {
0136             activity = activities.currentActivity();
0137         }
0138 
0139         static const auto queryString = QStringLiteral(
0140             "SELECT targettedResource "
0141             "FROM ResourceLink "
0142             "WHERE usedActivity = '%1' "
0143             "AND initiatingAgent = \":global\" ");
0144 
0145         auto query = database->execQuery(queryString.arg(activity));
0146 
0147         for (const auto &result : query) {
0148             auto path = result[0].toString();
0149 
0150             if (!QFile(path).exists())
0151                 continue;
0152 
0153             KIO::UDSEntry uds;
0154 
0155             udslist << d->filesystemEntry(path);
0156         }
0157 
0158         listEntries(udslist);
0159         return KIO::WorkerResult::pass();
0160     }
0161 
0162     case ActivitiesProtocolApi::ActivityPathItem:
0163         return ForwardingWorkerBase::listDir(QUrl::fromLocalFile(path));
0164     }
0165 
0166     Q_UNREACHABLE();
0167     return KIO::WorkerResult::fail();
0168 }
0169 
0170 KIO::WorkerResult ActivitiesProtocol::stat(const QUrl &url)
0171 {
0172     QString activity;
0173 
0174     switch (d->pathType(url, &activity)) {
0175     case ActivitiesProtocolApi::RootItem: {
0176         QString dirName = i18n("Activities");
0177         KIO::UDSEntry uds;
0178         uds.reserve(6);
0179         uds.fastInsert(KIO::UDSEntry::UDS_NAME, dirName);
0180         uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, dirName);
0181         uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_TYPE, dirName);
0182         uds.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("activities"));
0183         uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0184         uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0185 
0186         statEntry(uds);
0187 
0188         return KIO::WorkerResult::pass();
0189     }
0190 
0191     case ActivitiesProtocolApi::ActivityRootItem: {
0192         KActivities::Consumer activities;
0193         d->syncActivities(activities);
0194 
0195         if (activity == "current") {
0196             activity = activities.currentActivity();
0197         }
0198 
0199         statEntry(d->activityEntry(activity));
0200 
0201         return KIO::WorkerResult::pass();
0202     }
0203 
0204     case ActivitiesProtocolApi::ActivityPathItem:
0205         return ForwardingWorkerBase::stat(url);
0206     }
0207 
0208     Q_UNREACHABLE();
0209     return KIO::WorkerResult::fail();
0210 }
0211 
0212 KIO::WorkerResult ActivitiesProtocol::mimetype(const QUrl &url)
0213 {
0214     switch (d->pathType(url)) {
0215     case ActivitiesProtocolApi::RootItem:
0216     case ActivitiesProtocolApi::ActivityRootItem:
0217         mimeType(QStringLiteral("inode/directory"));
0218         return KIO::WorkerResult::pass();
0219 
0220     case ActivitiesProtocolApi::ActivityPathItem:
0221         return ForwardingWorkerBase::mimetype(url);
0222     }
0223 
0224     Q_UNREACHABLE();
0225     return KIO::WorkerResult::fail();
0226 }
0227 
0228 #include "KioActivities.moc"
0229 #include "moc_KioActivities.cpp"