File indexing completed on 2024-04-28 08:49:45

0001 /*
0002  *   SPDX-FileCopyrightText: 2012-2016 Ivan Cukic <ivan.cukic@kde.org>
0003  *   SPDX-FileCopyrightText: 2022 Alex Kuznetsov <alex@vxpro.io>
0004  *
0005  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006  */
0007 
0008 #include "KioActivitiesApi.h"
0009 #include "KioActivities.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 #include <QUrl>
0024 
0025 #include <KIO/StatJob>
0026 #include <KLocalizedString>
0027 #include <KUser>
0028 
0029 #include <common/database/Database.h>
0030 #include <utils/d_ptr_implementation.h>
0031 #include <utils/qsqlquery_iterator.h>
0032 
0033 #include <PlasmaActivities/Consumer>
0034 #include <PlasmaActivities/Info>
0035 
0036 #include <QProcess>
0037 
0038 ActivitiesProtocolApi::ActivitiesProtocolApi()
0039 {
0040 }
0041 
0042 ActivitiesProtocolApi::PathType ActivitiesProtocolApi::pathType(const QUrl &url, QString *activity, QString *filePath) const
0043 {
0044     const auto fullPath = url.adjusted(QUrl::StripTrailingSlash).path();
0045     const auto path = QStringView(fullPath).mid(fullPath.startsWith(QLatin1Char('/')) ? 1 : 0);
0046 
0047     if (activity && !path.isEmpty()) {
0048         *activity = path.mid(0, path.indexOf(QStringLiteral("/"))).toString();
0049     }
0050 
0051     if (filePath) {
0052         auto strippedPath = path.mid(path.indexOf(QStringLiteral("/")) + 1);
0053         auto splitPosition = strippedPath.indexOf(QStringLiteral("/"));
0054 
0055         if (splitPosition == -1) {
0056             // if we have only one path segment
0057             *filePath = demangledPath(strippedPath.toString());
0058 
0059         } else {
0060             // if we have sub-paths
0061             auto head = strippedPath.mid(0, splitPosition);
0062             auto tail = strippedPath.mid(splitPosition);
0063 
0064             *filePath = demangledPath(head.toString()) + tail.toString();
0065         }
0066     }
0067 
0068     return path.length() == 0 ? RootItem : path.contains(QStringLiteral("/")) ? ActivityPathItem : ActivityRootItem;
0069 }
0070 
0071 void ActivitiesProtocolApi::syncActivities(KActivities::Consumer &activities)
0072 {
0073     // We need to use the consumer in a synchronized way
0074     while (activities.serviceStatus() == KActivities::Consumer::Unknown) {
0075         QCoreApplication::processEvents();
0076     }
0077 }
0078 
0079 KIO::UDSEntry ActivitiesProtocolApi::activityEntry(const QString &activity)
0080 {
0081     KIO::UDSEntry uds;
0082     uds.reserve(8);
0083     KActivities::Info activityInfo(activity);
0084     uds.fastInsert(KIO::UDSEntry::UDS_NAME, activity);
0085     uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, activityInfo.name());
0086     uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_TYPE, i18n("Activity"));
0087     uds.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, activityInfo.icon());
0088     uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0089     uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0090     uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0500);
0091     uds.fastInsert(KIO::UDSEntry::UDS_USER, KUser().loginName());
0092     return uds;
0093 }
0094 
0095 KIO::UDSEntry ActivitiesProtocolApi::filesystemEntry(const QString &path)
0096 {
0097     KIO::UDSEntry uds;
0098     auto url = QUrl::fromLocalFile(path);
0099 
0100     if (KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo)) {
0101         QScopedPointer<KIO::StatJob> sp(job);
0102         job->setAutoDelete(false);
0103         if (job->exec()) {
0104             uds = job->statResult();
0105         }
0106     }
0107 
0108     auto mangled = mangledPath(path);
0109     // QProcess::execute("kdialog", { "--passivepopup", mangled });
0110 
0111     uds.replace(KIO::UDSEntry::UDS_NAME, mangled);
0112     uds.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, url.fileName());
0113     uds.replace(KIO::UDSEntry::UDS_TARGET_URL, url.url());
0114     uds.replace(KIO::UDSEntry::UDS_LOCAL_PATH, path);
0115 
0116     return uds;
0117 }
0118 
0119 QString ActivitiesProtocolApi::mangledPath(const QString &path) const
0120 {
0121     // return QString::fromUtf8(QUrl::toPercentEncoding(path));
0122     return QString::fromLatin1(path.toUtf8().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
0123 }
0124 
0125 QString ActivitiesProtocolApi::demangledPath(const QString &mangled) const
0126 {
0127     // return QUrl::fromPercentEncoding(mangled.toUtf8());
0128     return QString::fromUtf8(QByteArray::fromBase64(mangled.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
0129 }