File indexing completed on 2024-04-28 16:43:20

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.slave.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 slave(argv[2], argv[3]);
0039     slave.dispatchLoop();
0040     return 0;
0041 }
0042 
0043 KioBluetooth::KioBluetooth(const QByteArray &pool, const QByteArray &app)
0044     : SlaveBase(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.kded5"), 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 void 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         finished();
0101         return;
0102     }
0103 
0104     const QList<Service> &services = getSupportedServices(info.value(QStringLiteral("UUIDs")).split(QLatin1Char(',')));
0105 
0106     qCDebug(BLUETOOTH) << "Num of supported services: " << services.size();
0107 
0108     int i = 1;
0109     totalSize(services.count());
0110 
0111     for (const Service &service : services) {
0112         KIO::UDSEntry entry;
0113         entry.fastInsert(KIO::UDSEntry::UDS_NAME, service.uuid);
0114         entry.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, service.name);
0115         entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, service.icon);
0116         entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
0117 
0118         // If it is browse files, act as a folder
0119         if (service.uuid == BluezQt::Services::ObexFileTransfer) {
0120             QUrl obexUrl;
0121             obexUrl.setScheme(QStringLiteral("obexftp"));
0122             obexUrl.setHost(m_currentHostname.replace(QLatin1Char(':'), QLatin1Char('-')).toUpper());
0123             entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0124             entry.fastInsert(KIO::UDSEntry::UDS_URL, obexUrl.toString());
0125         } else {
0126             entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
0127         }
0128 
0129         if (service.mimetype.isEmpty()) {
0130             entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/vnd.kde.bluedevil.service"));
0131         } else {
0132             entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, service.mimetype);
0133         }
0134 
0135         listEntry(entry);
0136         processedSize(i++);
0137     }
0138 
0139     infoMessage(QString());
0140     finished();
0141 }
0142 
0143 void KioBluetooth::listDownload()
0144 {
0145     KIO::UDSEntry entry;
0146     entry.clear();
0147     entry.fastInsert(KIO::UDSEntry::UDS_URL, FileReceiverSettings::saveUrl().toDisplayString());
0148     entry.fastInsert(KIO::UDSEntry::UDS_NAME, i18n("Received Files"));
0149     entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("folder-downloads"));
0150     entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0151     entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
0152     entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0153     listEntry(entry);
0154 }
0155 
0156 void KioBluetooth::listDevices()
0157 {
0158     qCDebug(BLUETOOTH) << "Asking kded for devices";
0159     const QMapDeviceInfo &devices = m_kded->allDevices().value();
0160     qCDebug(BLUETOOTH) << devices.keys();
0161 
0162     for (const DeviceInfo &device : devices) {
0163         listDevice(device);
0164     }
0165 
0166     m_kded->startDiscovering(10 * 1000);
0167 
0168     infoMessage(i18n("Scanning for new devices…"));
0169     finished();
0170 }
0171 
0172 void KioBluetooth::listDevice(const DeviceInfo device)
0173 {
0174     qCDebug(BLUETOOTH) << device;
0175     if (getSupportedServices(device[QStringLiteral("UUIDs")].split(QStringLiteral(","))).isEmpty()) {
0176         return;
0177     }
0178     QString target = QStringLiteral("bluetooth://");
0179     target.append(QString(device[QStringLiteral("address")]).replace(QLatin1Char(':'), QLatin1Char('-')) + QLatin1Char('/'));
0180 
0181     KIO::UDSEntry entry;
0182     entry.fastInsert(KIO::UDSEntry::UDS_URL, target);
0183     entry.fastInsert(KIO::UDSEntry::UDS_NAME, device[QStringLiteral("name")]);
0184     entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, device[QStringLiteral("icon")]);
0185     entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0186     entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
0187     entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/vnd.kde.bluedevil.device"));
0188     listEntry(entry);
0189 }
0190 
0191 void KioBluetooth::listDir(const QUrl &url)
0192 {
0193     qCDebug(BLUETOOTH) << "Listing..." << url;
0194 
0195     // Url is not used here because all we could care about the url is the host, and that's already
0196     // handled in @p setHost
0197     Q_UNUSED(url);
0198 
0199     // If we are not online (ie. there's no working bluetooth adapter), list an empty dir
0200     qCDebug(BLUETOOTH) << m_kded->isOnline().value();
0201     if (!m_kded->isOnline().value()) {
0202         infoMessage(i18n("No Bluetooth adapters have been found."));
0203         finished();
0204         return;
0205     }
0206 
0207     if (!m_hasCurrentHost) {
0208         listDownload();
0209         listDevices();
0210     } else {
0211         listRemoteDeviceServices();
0212     }
0213 }
0214 
0215 void KioBluetooth::stat(const QUrl &url)
0216 {
0217     qCDebug(BLUETOOTH) << "Stat: " << url;
0218     finished();
0219 }
0220 
0221 void KioBluetooth::get(const QUrl &url)
0222 {
0223     m_kded->stopDiscovering();
0224     qCDebug(BLUETOOTH) << "Get: " << url;
0225     qCDebug(BLUETOOTH) << m_supportedServices.value(url.fileName()).mimetype;
0226     mimeType(m_supportedServices.value(url.fileName()).mimetype);
0227     finished();
0228 }
0229 
0230 void KioBluetooth::setHost(const QString &hostname, quint16 port, const QString &user, const QString &pass)
0231 {
0232     qCDebug(BLUETOOTH) << "Setting host: " << hostname;
0233 
0234     // In this kio only the hostname (constHostname) is used
0235     Q_UNUSED(port)
0236     Q_UNUSED(user)
0237     Q_UNUSED(pass)
0238 
0239     if (hostname.isEmpty()) {
0240         m_hasCurrentHost = false;
0241     } else {
0242         m_hasCurrentHost = true;
0243 
0244         m_currentHostname = hostname;
0245         m_currentHostAddress = hostname.toUpper();
0246         m_currentHostAddress.replace(QLatin1Char('-'), QLatin1Char(':'));
0247     }
0248 }
0249 
0250 Q_LOGGING_CATEGORY(BLUETOOTH, "bluedevil.kio_bluetooth")
0251 
0252 #include "kiobluetooth.moc"