File indexing completed on 2024-04-21 05:01:38
0001 /* 0002 Provides an interface to the computer's hardware 0003 0004 SPDX-FileCopyrightText: 2015-2023 Alexander Reinholdt <alexander.reinholdt@kdemail.net> 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 // application specific includes 0009 #include "smb4khardwareinterface.h" 0010 0011 // system includes 0012 #include <unistd.h> 0013 0014 // Qt includes 0015 #include <QDBusInterface> 0016 #include <QDBusReply> 0017 #include <QDBusUnixFileDescriptor> 0018 #include <QDebug> 0019 #include <QNetworkInterface> 0020 #include <QString> 0021 #include <QStringList> 0022 #include <QTimer> 0023 0024 // KDE includes 0025 #include <Solid/Device> 0026 #include <Solid/DeviceInterface> 0027 #include <Solid/DeviceNotifier> 0028 #include <Solid/NetworkShare> 0029 #include <solid_version.h> 0030 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0031 #include <KMountPoint> 0032 #endif 0033 0034 class Smb4KHardwareInterfacePrivate 0035 { 0036 public: 0037 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0038 QStringList mountPoints; 0039 #endif 0040 QScopedPointer<QDBusInterface> dbusInterface; 0041 QDBusUnixFileDescriptor fileDescriptor; 0042 bool systemOnline; 0043 QStringList udis; 0044 }; 0045 0046 class Smb4KHardwareInterfaceStatic 0047 { 0048 public: 0049 Smb4KHardwareInterface instance; 0050 }; 0051 0052 Q_GLOBAL_STATIC(Smb4KHardwareInterfaceStatic, p); 0053 0054 Smb4KHardwareInterface::Smb4KHardwareInterface(QObject *parent) 0055 : QObject(parent) 0056 , d(new Smb4KHardwareInterfacePrivate) 0057 { 0058 // 0059 // Initialize some members 0060 // 0061 d->systemOnline = false; 0062 d->fileDescriptor.setFileDescriptor(-1); 0063 0064 // 0065 // Set up the DBUS interface 0066 // 0067 d->dbusInterface.reset(new QDBusInterface(QStringLiteral("org.freedesktop.login1"), 0068 QStringLiteral("/org/freedesktop/login1"), 0069 QStringLiteral("org.freedesktop.login1.Manager"), 0070 QDBusConnection::systemBus(), 0071 this)); 0072 0073 if (!d->dbusInterface->isValid()) { 0074 d->dbusInterface.reset(new QDBusInterface(QStringLiteral("org.freedesktop.ConsoleKit"), 0075 QStringLiteral("/org/freedesktop/ConsoleKit/Manager"), 0076 QStringLiteral("org.freedesktop.ConsoleKit.Manager"), 0077 QDBusConnection::systemBus(), 0078 this)); 0079 } 0080 0081 // 0082 // Get the initial list of udis for network shares 0083 // 0084 QList<Solid::Device> allDevices = Solid::Device::allDevices(); 0085 0086 for (const Solid::Device &device : qAsConst(allDevices)) { 0087 const Solid::DeviceInterface *iface = device.asDeviceInterface(Solid::DeviceInterface::NetworkShare); 0088 const Solid::NetworkShare *networkShare = qobject_cast<const Solid::NetworkShare *>(iface); 0089 0090 if (networkShare && (networkShare->type() == Solid::NetworkShare::Cifs || networkShare->type() == Solid::NetworkShare::Smb3)) { 0091 d->udis << device.udi(); 0092 } 0093 } 0094 0095 // 0096 // Connections 0097 // 0098 connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), this, SLOT(slotDeviceAdded(QString))); 0099 connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), this, SLOT(slotDeviceRemoved(QString))); 0100 0101 // 0102 // Check the online state 0103 // 0104 checkOnlineState(false); 0105 0106 // 0107 // Start the timer to continously check the online state 0108 // and, under FreeBSD, additionally the mounted shares. 0109 // 0110 startTimer(1000); 0111 } 0112 0113 Smb4KHardwareInterface::~Smb4KHardwareInterface() 0114 { 0115 } 0116 0117 Smb4KHardwareInterface *Smb4KHardwareInterface::self() 0118 { 0119 return &p->instance; 0120 } 0121 0122 bool Smb4KHardwareInterface::isOnline() const 0123 { 0124 return d->systemOnline; 0125 } 0126 0127 void Smb4KHardwareInterface::inhibit() 0128 { 0129 if (d->fileDescriptor.isValid()) { 0130 return; 0131 } 0132 0133 if (d->dbusInterface->isValid()) { 0134 QVariantList args; 0135 args << QStringLiteral("shutdown:sleep"); 0136 args << QStringLiteral("Smb4K"); 0137 args << QStringLiteral("Mounting or unmounting in progress"); 0138 args << QStringLiteral("delay"); 0139 0140 QDBusReply<QDBusUnixFileDescriptor> descriptor = d->dbusInterface->callWithArgumentList(QDBus::Block, QStringLiteral("Inhibit"), args); 0141 0142 if (descriptor.isValid()) { 0143 d->fileDescriptor = descriptor.value(); 0144 } 0145 } 0146 } 0147 0148 void Smb4KHardwareInterface::uninhibit() 0149 { 0150 if (!d->fileDescriptor.isValid()) { 0151 return; 0152 } 0153 0154 if (d->dbusInterface->isValid()) { 0155 close(d->fileDescriptor.fileDescriptor()); 0156 d->fileDescriptor.setFileDescriptor(-1); 0157 } 0158 } 0159 0160 void Smb4KHardwareInterface::checkOnlineState(bool emitSignal) 0161 { 0162 bool online = false; 0163 QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); 0164 0165 for (const QNetworkInterface &interface : qAsConst(interfaces)) { 0166 if (interface.isValid() && interface.type() != QNetworkInterface::Loopback && interface.flags() & QNetworkInterface::IsRunning) { 0167 online = true; 0168 break; 0169 } 0170 } 0171 0172 if (online != d->systemOnline) { 0173 d->systemOnline = online; 0174 0175 if (emitSignal) { 0176 Q_EMIT onlineStateChanged(d->systemOnline); 0177 } 0178 } 0179 } 0180 0181 void Smb4KHardwareInterface::timerEvent(QTimerEvent *event) 0182 { 0183 Q_UNUSED(event); 0184 0185 checkOnlineState(); 0186 0187 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0188 // NOTE: Using FreeBSD 11 with KF 5.27, Solid is not able to detect mounted shares. 0189 // Thus, we check here whether shares have been mounted or unmounted. 0190 // This is a hack and should be removed as soon as possible. 0191 KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::BasicInfoNeeded | KMountPoint::NeedMountOptions); 0192 QStringList mountPointList, alreadyMounted; 0193 0194 for (const QExplicitlySharedDataPointer<KMountPoint> &mountPoint : mountPoints) { 0195 if (mountPoint->mountType() == QStringLiteral("smbfs")) { 0196 mountPointList.append(mountPoint->mountPoint()); 0197 } 0198 } 0199 0200 QMutableStringListIterator it(mountPointList); 0201 0202 while (it.hasNext()) { 0203 QString mp = it.next(); 0204 int index = -1; 0205 0206 if ((index = d->mountPoints.indexOf(mp)) != -1) { 0207 d->mountPoints.removeAt(index); 0208 alreadyMounted.append(mp); 0209 it.remove(); 0210 } 0211 } 0212 0213 if (!d->mountPoints.isEmpty()) { 0214 Q_EMIT networkShareRemoved(); 0215 } 0216 0217 if (!mountPointList.isEmpty()) { 0218 Q_EMIT networkShareAdded(); 0219 } 0220 0221 d->mountPoints.clear(); 0222 d->mountPoints.append(alreadyMounted); 0223 d->mountPoints.append(mountPointList); 0224 #endif 0225 } 0226 0227 void Smb4KHardwareInterface::slotDeviceAdded(const QString &udi) 0228 { 0229 Solid::Device device(udi); 0230 0231 const Solid::DeviceInterface *iface = device.asDeviceInterface(Solid::DeviceInterface::NetworkShare); 0232 const Solid::NetworkShare *networkShare = qobject_cast<const Solid::NetworkShare *>(iface); 0233 0234 if (networkShare && (networkShare->type() == Solid::NetworkShare::Cifs || networkShare->type() == Solid::NetworkShare::Smb3)) { 0235 d->udis << udi; 0236 Q_EMIT networkShareAdded(); 0237 } 0238 } 0239 0240 void Smb4KHardwareInterface::slotDeviceRemoved(const QString &udi) 0241 { 0242 if (d->udis.contains(udi)) { 0243 Q_EMIT networkShareRemoved(); 0244 d->udis.removeOne(udi); 0245 } 0246 }