File indexing completed on 2024-04-28 05:26:13

0001 /*
0002  *  SPDX-FileCopyrightText: 2010-2012 Alejandro Fiestas Olivares <afiestas@kde.org>
0003  *  SPDX-FileCopyrightText: 2010 Eduardo Robles Elvira <edulix@gmail.com>
0004  *  SPDX-FileCopyrightText: 2010 Rafael Fernández López <ereslibre@kde.org>
0005  *  SPDX-FileCopyrightText: 2010 UFO Coders <info@ufocoders.com>
0006  *
0007  *  SPDX-License-Identifier: GPL-2.0-or-later
0008  */
0009 
0010 #include "kiobluetooth.h"
0011 #include "filereceiversettings.h"
0012 #include "version.h"
0013 
0014 #include <QCoreApplication>
0015 #include <QDBusMetaType>
0016 #include <QThread>
0017 
0018 #include <KLocalizedString>
0019 
0020 #include <BluezQt/Services>
0021 
0022 // Pseudo plugin class to embed meta data
0023 class KIOPluginForMetaData : public QObject
0024 {
0025     Q_OBJECT
0026     Q_PLUGIN_METADATA(IID "org.kde.kio.worker.bluetooth" FILE "bluetooth.json")
0027 };
0028 
0029 extern "C" int Q_DECL_EXPORT kdemain(int argc, char **argv)
0030 {
0031     QCoreApplication app(argc, argv);
0032 
0033     if (argc != 4) {
0034         fprintf(stderr, "Usage: kio_bluetooth protocol domain-socket1 domain-socket2\n");
0035         exit(-1);
0036     }
0037 
0038     KioBluetooth worker(argv[2], argv[3]);
0039     worker.dispatchLoop();
0040     return 0;
0041 }
0042 
0043 KioBluetooth::KioBluetooth(const QByteArray &pool, const QByteArray &app)
0044     : KIO::WorkerBase(QByteArrayLiteral("bluetooth"), pool, app)
0045 {
0046     qDBusRegisterMetaType<DeviceInfo>();
0047     qDBusRegisterMetaType<QMapDeviceInfo>();
0048 
0049     m_hasCurrentHost = false;
0050 
0051     Service sendFile;
0052     sendFile.name = i18n("Send File");
0053     sendFile.icon = QStringLiteral("edit-copy");
0054     sendFile.mimetype = QStringLiteral("application/vnd.kde.bluedevil-sendfile");
0055     sendFile.uuid = BluezQt::Services::ObexObjectPush;
0056 
0057     Service browseFiles;
0058     browseFiles.name = i18n("Browse Files");
0059     browseFiles.icon = QStringLiteral("edit-find");
0060     browseFiles.mimetype = QString();
0061     browseFiles.uuid = BluezQt::Services::ObexFileTransfer;
0062 
0063     m_supportedServices.insert(sendFile.uuid, sendFile);
0064     m_supportedServices.insert(browseFiles.uuid, browseFiles);
0065 
0066     qCDebug(BLUETOOTH) << "Kio Bluetooth instanced!";
0067 
0068     m_kded = new org::kde::BlueDevil(QStringLiteral("org.kde.kded6"), QStringLiteral("/modules/bluedevil"), QDBusConnection::sessionBus());
0069 
0070     if (!m_kded->isOnline()) {
0071         qCDebug(BLUETOOTH) << "Bluetooth is offline";
0072         infoMessage(i18n("No Bluetooth adapters have been found."));
0073         return;
0074     }
0075 }
0076 
0077 QList<KioBluetooth::Service> KioBluetooth::getSupportedServices(const QStringList &uuids)
0078 {
0079     qCDebug(BLUETOOTH) << "supported services: " << uuids;
0080 
0081     QList<Service> retValue;
0082     for (const QString &uuid : uuids) {
0083         if (m_supportedServices.contains(uuid)) {
0084             retValue << m_supportedServices[uuid];
0085         }
0086     }
0087     return retValue;
0088 }
0089 
0090 KIO::WorkerResult KioBluetooth::listRemoteDeviceServices()
0091 {
0092     infoMessage(i18n("Retrieving services…"));
0093 
0094     qCDebug(BLUETOOTH) << "Listing remote devices";
0095 
0096     const DeviceInfo &info = m_kded->device(m_currentHostAddress).value();
0097     if (info.isEmpty()) {
0098         qCDebug(BLUETOOTH) << "Invalid hostname!";
0099         infoMessage(i18n("This address is unavailable."));
0100         return KIO::WorkerResult::pass();
0101     }
0102 
0103     const QList<Service> &services = getSupportedServices(info.value(QStringLiteral("UUIDs")).split(QLatin1Char(',')));
0104 
0105     qCDebug(BLUETOOTH) << "Num of supported services: " << services.size();
0106 
0107     int i = 1;
0108     totalSize(services.count());
0109 
0110     for (const Service &service : services) {
0111         KIO::UDSEntry entry;
0112         entry.fastInsert(KIO::UDSEntry::UDS_NAME, service.uuid);
0113         entry.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, service.name);
0114         entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, service.icon);
0115         entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
0116 
0117         // If it is browse files, act as a folder
0118         if (service.uuid == BluezQt::Services::ObexFileTransfer) {
0119             QUrl obexUrl;
0120             obexUrl.setScheme(QStringLiteral("obexftp"));
0121             obexUrl.setHost(m_currentHostname.replace(QLatin1Char(':'), QLatin1Char('-')).toUpper());
0122             entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0123             entry.fastInsert(KIO::UDSEntry::UDS_URL, obexUrl.toString());
0124         } else {
0125             entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
0126         }
0127 
0128         if (service.mimetype.isEmpty()) {
0129             entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/vnd.kde.bluedevil.service"));
0130         } else {
0131             entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, service.mimetype);
0132         }
0133 
0134         listEntry(entry);
0135         processedSize(i++);
0136     }
0137 
0138     infoMessage(QString());
0139     return KIO::WorkerResult::pass();
0140 }
0141 
0142 void KioBluetooth::listDownload()
0143 {
0144     KIO::UDSEntry entry;
0145     entry.clear();
0146     entry.fastInsert(KIO::UDSEntry::UDS_URL, FileReceiverSettings::saveUrl().toDisplayString());
0147     entry.fastInsert(KIO::UDSEntry::UDS_NAME, i18n("Received Files"));
0148     entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("folder-downloads"));
0149     entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0150     entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
0151     entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0152     listEntry(entry);
0153 }
0154 
0155 void KioBluetooth::listDevices()
0156 {
0157     qCDebug(BLUETOOTH) << "Asking kded for devices";
0158     const QMapDeviceInfo &devices = m_kded->allDevices().value();
0159     qCDebug(BLUETOOTH) << devices.keys();
0160 
0161     for (const DeviceInfo &device : devices) {
0162         listDevice(device);
0163     }
0164 
0165     m_kded->startDiscovering(10 * 1000);
0166 
0167     infoMessage(i18n("Scanning for new devices…"));
0168 }
0169 
0170 void KioBluetooth::listDevice(const DeviceInfo device)
0171 {
0172     qCDebug(BLUETOOTH) << device;
0173     if (getSupportedServices(device[QStringLiteral("UUIDs")].split(QStringLiteral(","))).isEmpty()) {
0174         return;
0175     }
0176     QString target = QStringLiteral("bluetooth://");
0177     target.append(QString(device[QStringLiteral("address")]).replace(QLatin1Char(':'), QLatin1Char('-')) + QLatin1Char('/'));
0178 
0179     KIO::UDSEntry entry;
0180     entry.fastInsert(KIO::UDSEntry::UDS_URL, target);
0181     entry.fastInsert(KIO::UDSEntry::UDS_NAME, device[QStringLiteral("name")]);
0182     entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, device[QStringLiteral("icon")]);
0183     entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0184     entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
0185     entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/vnd.kde.bluedevil.device"));
0186     listEntry(entry);
0187 }
0188 
0189 KIO::WorkerResult KioBluetooth::listDir(const QUrl &url)
0190 {
0191     qCDebug(BLUETOOTH) << "Listing..." << url;
0192 
0193     // Url is not used here because all we could care about the url is the host, and that's already
0194     // handled in @p setHost
0195     Q_UNUSED(url);
0196 
0197     // If we are not online (ie. there's no working bluetooth adapter), list an empty dir
0198     qCDebug(BLUETOOTH) << m_kded->isOnline().value();
0199     if (!m_kded->isOnline().value()) {
0200         infoMessage(i18n("No Bluetooth adapters have been found."));
0201         return KIO::WorkerResult::pass();
0202     }
0203 
0204     if (!m_hasCurrentHost) {
0205         listDownload();
0206         listDevices();
0207         return KIO::WorkerResult::pass();
0208     } else {
0209         return listRemoteDeviceServices();
0210     }
0211 }
0212 
0213 KIO::WorkerResult KioBluetooth::stat(const QUrl &url)
0214 {
0215     qCDebug(BLUETOOTH) << "Stat: " << url;
0216     return KIO::WorkerResult::pass();
0217 }
0218 
0219 KIO::WorkerResult KioBluetooth::get(const QUrl &url)
0220 {
0221     m_kded->stopDiscovering();
0222     qCDebug(BLUETOOTH) << "Get: " << url;
0223     qCDebug(BLUETOOTH) << m_supportedServices.value(url.fileName()).mimetype;
0224     mimeType(m_supportedServices.value(url.fileName()).mimetype);
0225     return KIO::WorkerResult::pass();
0226 }
0227 
0228 void KioBluetooth::setHost(const QString &hostname, quint16 port, const QString &user, const QString &pass)
0229 {
0230     qCDebug(BLUETOOTH) << "Setting host: " << hostname;
0231 
0232     // In this kio only the hostname (constHostname) is used
0233     Q_UNUSED(port)
0234     Q_UNUSED(user)
0235     Q_UNUSED(pass)
0236 
0237     if (hostname.isEmpty()) {
0238         m_hasCurrentHost = false;
0239     } else {
0240         m_hasCurrentHost = true;
0241 
0242         m_currentHostname = hostname;
0243         m_currentHostAddress = hostname.toUpper();
0244         m_currentHostAddress.replace(QLatin1Char('-'), QLatin1Char(':'));
0245     }
0246 }
0247 
0248 Q_LOGGING_CATEGORY(BLUETOOTH, "bluedevil.kio_bluetooth")
0249 
0250 #include "kiobluetooth.moc"
0251 
0252 #include "moc_kiobluetooth.cpp"