File indexing completed on 2023-09-24 08:52:41
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "kiokdeconnect.h" 0008 0009 #include <QDBusMetaType> 0010 #include <QThread> 0011 0012 #include <KLocalizedString> 0013 0014 #include <QDebug> 0015 #include <QtPlugin> 0016 0017 #include "kdeconnectkio_debug.h" 0018 0019 class KIOPluginForMetaData : public QObject 0020 { 0021 Q_OBJECT 0022 Q_PLUGIN_METADATA(IID "org.kde.kio.slave.kdeconnect" FILE "kdeconnect.json") 0023 }; 0024 0025 extern "C" int Q_DECL_EXPORT kdemain(int argc, char **argv) 0026 { 0027 QCoreApplication app(argc, argv); 0028 app.setApplicationName(QStringLiteral("kio_kdeconnect")); 0029 0030 if (argc != 4) { 0031 fprintf(stderr, "Usage: kio_kdeconnect protocol pool app\n"); 0032 exit(-1); 0033 } 0034 0035 KioKdeconnect worker(argv[2], argv[3]); 0036 worker.dispatchLoop(); 0037 return 0; 0038 } 0039 0040 // Some useful error mapping 0041 KIO::Error toKioError(const QDBusError::ErrorType type) 0042 { 0043 switch (type) { 0044 case QDBusError::NoError: 0045 return KIO::Error(KJob::NoError); 0046 case QDBusError::NoMemory: 0047 return KIO::ERR_OUT_OF_MEMORY; 0048 case QDBusError::Timeout: 0049 return KIO::ERR_SERVER_TIMEOUT; 0050 case QDBusError::TimedOut: 0051 return KIO::ERR_SERVER_TIMEOUT; 0052 default: 0053 return KIO::ERR_WORKER_DEFINED; 0054 }; 0055 }; 0056 0057 template<typename T> 0058 KIO::WorkerResult handleDBusError(QDBusReply<T> &reply) 0059 { 0060 if (!reply.isValid()) { 0061 qCDebug(KDECONNECT_KIO) << "Error in DBus request:" << reply.error(); 0062 return KIO::WorkerResult::fail(toKioError(reply.error().type()), reply.error().message()); 0063 } 0064 return KIO::WorkerResult::pass(); 0065 } 0066 0067 KioKdeconnect::KioKdeconnect(const QByteArray &pool, const QByteArray &app) 0068 : WorkerBase("kdeconnect", pool, app) 0069 , m_dbusInterface(new DaemonDbusInterface(this)) 0070 { 0071 } 0072 0073 KIO::WorkerResult KioKdeconnect::listAllDevices() 0074 { 0075 infoMessage(i18n("Listing devices...")); 0076 0077 // TODO: Change to all devices and show different icons for connected and disconnected? 0078 const QStringList devices = m_dbusInterface->devices(true, true); 0079 0080 for (const QString &deviceId : devices) { 0081 DeviceDbusInterface interface(deviceId); 0082 0083 if (!interface.hasPlugin(QStringLiteral("kdeconnect_sftp"))) 0084 continue; 0085 0086 const QString path = QStringLiteral("kdeconnect://").append(deviceId).append(QStringLiteral("/")); 0087 const QString name = interface.name(); 0088 const QString icon = QStringLiteral("kdeconnect"); 0089 0090 KIO::UDSEntry entry; 0091 entry.reserve(6); 0092 entry.fastInsert(KIO::UDSEntry::UDS_NAME, name); 0093 entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, icon); 0094 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, QT_STAT_DIR); 0095 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0096 QFileDevice::ReadOwner | QFileDevice::ExeOwner | QFileDevice::ReadGroup | QFileDevice::ExeGroup | QFileDevice::ReadOther 0097 | QFileDevice::ExeOther); 0098 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QLatin1String("")); 0099 entry.fastInsert(KIO::UDSEntry::UDS_URL, path); 0100 listEntry(entry); 0101 } 0102 0103 // We also need a non-null and writable UDSentry for "." 0104 KIO::UDSEntry entry; 0105 entry.reserve(4); 0106 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral(".")); 0107 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, QT_STAT_DIR); 0108 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, 0); 0109 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0110 QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner | QFileDevice::ReadGroup | QFileDevice::WriteGroup 0111 | QFileDevice::ExeGroup | QFileDevice::ReadOther | QFileDevice::ExeOther); 0112 listEntry(entry); 0113 0114 infoMessage(QLatin1String("")); 0115 return KIO::WorkerResult::pass(); 0116 } 0117 0118 KIO::WorkerResult KioKdeconnect::listDevice(const QString &device) 0119 { 0120 infoMessage(i18n("Accessing device...")); 0121 0122 qCDebug(KDECONNECT_KIO) << "ListDevice" << device; 0123 0124 SftpDbusInterface interface(device); 0125 0126 QDBusReply<bool> mountreply = interface.mountAndWait(); 0127 0128 if (mountreply.error().type() == QDBusError::UnknownObject) { 0129 DaemonDbusInterface daemon; 0130 0131 auto devsRepl = daemon.devices(false, false); 0132 devsRepl.waitForFinished(); 0133 0134 if (!devsRepl.value().contains(device)) { 0135 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("No such device: %0").arg(device)); 0136 } 0137 0138 DeviceDbusInterface dev(device); 0139 0140 if (!dev.isPaired()) { 0141 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("%0 is not paired").arg(dev.name())); 0142 } 0143 0144 if (!dev.isReachable()) { 0145 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("%0 is not connected").arg(dev.name())); 0146 } 0147 0148 if (!dev.hasPlugin(QStringLiteral("kdeconnect_sftp"))) { 0149 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("%0 has no Remote Filesystem plugin").arg(dev.name())); 0150 } 0151 } 0152 0153 if (auto result = handleDBusError(mountreply); !result.success()) { 0154 return result; 0155 } 0156 0157 if (!mountreply.value()) { 0158 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, interface.getMountError()); 0159 } 0160 0161 QDBusReply<QVariantMap> urlreply = interface.getDirectories(); 0162 0163 if (auto result = handleDBusError(urlreply); !result.success()) { 0164 return result; 0165 } 0166 0167 QVariantMap urls = urlreply.value(); 0168 0169 for (QVariantMap::iterator it = urls.begin(); it != urls.end(); ++it) { 0170 const QString path = it.key(); 0171 const QString name = it.value().toString(); 0172 const QString icon = QStringLiteral("folder"); 0173 0174 KIO::UDSEntry entry; 0175 entry.reserve(6); 0176 entry.fastInsert(KIO::UDSEntry::UDS_NAME, name); 0177 entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, icon); 0178 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, QT_STAT_DIR); 0179 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0180 QFileDevice::ReadOwner | QFileDevice::ExeOwner | QFileDevice::ReadGroup | QFileDevice::ExeGroup | QFileDevice::ReadOther 0181 | QFileDevice::ExeOther); 0182 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QLatin1String("")); 0183 entry.fastInsert(KIO::UDSEntry::UDS_URL, QUrl::fromLocalFile(path).toString()); 0184 listEntry(entry); 0185 } 0186 0187 // We also need a non-null and writable UDSentry for "." 0188 KIO::UDSEntry entry; 0189 entry.reserve(4); 0190 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral(".")); 0191 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, QT_STAT_DIR); 0192 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, 0); 0193 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0194 QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner | QFileDevice::ReadGroup | QFileDevice::WriteGroup 0195 | QFileDevice::ExeGroup | QFileDevice::ReadOther | QFileDevice::ExeOther); 0196 0197 listEntry(entry); 0198 0199 infoMessage(QLatin1String("")); 0200 return KIO::WorkerResult::pass(); 0201 } 0202 0203 KIO::WorkerResult KioKdeconnect::listDir(const QUrl &url) 0204 { 0205 qCDebug(KDECONNECT_KIO) << "Listing..." << url; 0206 0207 if (!m_dbusInterface->isValid()) { 0208 return KIO::WorkerResult::fail(KIO::Error::ERR_WORKER_DEFINED, i18n("Could not contact background service.")); 0209 } 0210 0211 QString currentDevice = url.host(); 0212 0213 if (currentDevice.isEmpty()) { 0214 return listAllDevices(); 0215 } else { 0216 return listDevice(currentDevice); 0217 } 0218 } 0219 0220 KIO::WorkerResult KioKdeconnect::stat(const QUrl &url) 0221 { 0222 qCDebug(KDECONNECT_KIO) << "Stat: " << url; 0223 0224 KIO::UDSEntry entry; 0225 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, QT_STAT_DIR); 0226 0227 QString currentDevice = url.host(); 0228 if (!currentDevice.isEmpty()) { 0229 SftpDbusInterface interface(currentDevice); 0230 0231 if (interface.isValid()) { 0232 entry.fastInsert(KIO::UDSEntry::UDS_LOCAL_PATH, interface.mountPoint()); 0233 0234 if (!interface.isMounted()) { 0235 interface.mount(); 0236 } 0237 } 0238 } 0239 0240 statEntry(entry); 0241 0242 return KIO::WorkerResult::pass(); 0243 } 0244 0245 KIO::WorkerResult KioKdeconnect::get(const QUrl &url) 0246 { 0247 qCDebug(KDECONNECT_KIO) << "Get: " << url; 0248 mimeType(QLatin1String("")); 0249 return KIO::WorkerResult::pass(); 0250 } 0251 0252 // needed for JSON file embedding 0253 #include "kiokdeconnect.moc"