File indexing completed on 2024-05-12 05:37:18

0001 /*
0002     SPDX-FileCopyrightText: 2005 Jean-Remy Falleri <jr.falleri@laposte.net>
0003     SPDX-FileCopyrightText: 2005-2007 Kevin Ottens <ervin@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "deviceserviceaction.h"
0009 
0010 #include <QDebug>
0011 
0012 #include <KApplicationTrader>
0013 #include <KConfigGroup>
0014 #include <KDesktopFile>
0015 #include <KIO/CommandLauncherJob>
0016 #include <KLocalizedString>
0017 #include <KNotificationJobUiDelegate>
0018 #include <KService>
0019 #include <kmacroexpander.h>
0020 #include <solid/block.h>
0021 #include <solid/device.h>
0022 #include <solid/storageaccess.h>
0023 
0024 class MacroExpander : public KMacroExpanderBase
0025 {
0026 public:
0027     MacroExpander(const Solid::Device &device)
0028         : KMacroExpanderBase('%')
0029         , m_device(device)
0030     {
0031     }
0032 
0033 protected:
0034     int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
0035 
0036 private:
0037     Solid::Device m_device;
0038 };
0039 
0040 class DelayedExecutor : public QObject
0041 {
0042     Q_OBJECT
0043 public:
0044     DelayedExecutor(const KServiceAction &service, Solid::Device &device);
0045 
0046 private Q_SLOTS:
0047     void _k_storageSetupDone(Solid::ErrorType error, QVariant errorData, const QString &udi);
0048 
0049 private:
0050     void delayedExecute(const QString &udi);
0051 
0052     KServiceAction m_service;
0053 };
0054 
0055 void DeviceServiceAction::execute(Solid::Device &device)
0056 {
0057     new DelayedExecutor(m_service, device);
0058 }
0059 
0060 void DelayedExecutor::_k_storageSetupDone(Solid::ErrorType error, QVariant errorData, const QString &udi)
0061 {
0062     Q_UNUSED(errorData);
0063 
0064     if (!error) {
0065         delayedExecute(udi);
0066     }
0067 }
0068 
0069 void DeviceServiceAction::setService(const KServiceAction &service)
0070 {
0071     m_service = service;
0072 }
0073 
0074 KServiceAction DeviceServiceAction::service() const
0075 {
0076     return m_service;
0077 }
0078 
0079 int MacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
0080 {
0081     ushort option = str[pos + 1].unicode();
0082 
0083     switch (option) {
0084     case 'f': // Filepath
0085     case 'F': // case insensitive
0086         if (m_device.is<Solid::StorageAccess>()) {
0087             ret << m_device.as<Solid::StorageAccess>()->filePath();
0088         } else {
0089             qWarning() << "DeviceServiceAction::execute: " << m_device.udi() << " is not a StorageAccess device";
0090         }
0091         break;
0092     case 'd': // Device node
0093     case 'D': // case insensitive
0094         if (m_device.is<Solid::Block>()) {
0095             ret << m_device.as<Solid::Block>()->device();
0096         } else {
0097             qWarning() << "DeviceServiceAction::execute: " << m_device.udi() << " is not a Block device";
0098         }
0099         break;
0100     case 'i': // UDI
0101     case 'I': // case insensitive
0102         ret << m_device.udi();
0103         break;
0104     case '%':
0105         ret = QStringList(QLatin1String("%"));
0106         break;
0107     default:
0108         return -2; // subst with same and skip
0109     }
0110     return 2;
0111 }
0112 
0113 DelayedExecutor::DelayedExecutor(const KServiceAction &service, Solid::Device &device)
0114     : m_service(service)
0115 {
0116     if (device.is<Solid::StorageAccess>() && !device.as<Solid::StorageAccess>()->isAccessible()) {
0117         Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
0118 
0119         connect(access, &Solid::StorageAccess::setupDone, this, &DelayedExecutor::_k_storageSetupDone);
0120 
0121         access->setup();
0122     } else {
0123         delayedExecute(device.udi());
0124     }
0125 }
0126 
0127 void DelayedExecutor::delayedExecute(const QString &udi)
0128 {
0129     Solid::Device device(udi);
0130 
0131     qWarning() << "About the execute the service...";
0132     QString exec = m_service.exec();
0133     qWarning() << "Executed the service!!!";
0134     MacroExpander mx(device);
0135     mx.expandMacrosShellQuote(exec);
0136 
0137     KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(exec);
0138     job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled));
0139 
0140     // To make xdg-activation and startup feedback work we need to pass the desktop file name of what we are launching
0141     if (m_service.service()->storageId().endsWith(QLatin1String("openWithFileManager.desktop"))) {
0142         // We know that we are going to launch the default file manager, so query the desktop file name of that
0143         const KService::Ptr defaultFileManager = KApplicationTrader::preferredService(QStringLiteral("inode/directory"));
0144         job->setDesktopName(defaultFileManager->desktopEntryName());
0145     } else {
0146         // Read the app that will be launched from the desktop file
0147         KDesktopFile desktopFile(m_service.service()->storageId());
0148         job->setDesktopName(desktopFile.desktopGroup().readEntry("X-KDE-AliasFor"));
0149     }
0150 
0151     job->start();
0152 
0153     deleteLater();
0154 }
0155 
0156 #include "deviceserviceaction.moc"