File indexing completed on 2024-03-24 16:27:21

0001 /***************************************************************************
0002     Provides an interface to the computer's hardware
0003                              -------------------
0004     begin                : Die Jul 14 2015
0005     copyright            : (C) 2015-2020 by Alexander Reinholdt
0006     email                : alexander.reinholdt@kdemail.net
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *   This program is free software; you can redistribute it and/or modify  *
0011  *   it under the terms of the GNU General Public License as published by  *
0012  *   the Free Software Foundation; either version 2 of the License, or     *
0013  *   (at your option) any later version.                                   *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful, but   *
0016  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
0018  *   General Public License for more details.                              *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program; if not, write to the                         *
0022  *   Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,*
0023  *   MA 02110-1335, USA                                                    *
0024  ***************************************************************************/
0025 
0026 // application specific includes
0027 #include "smb4khardwareinterface.h"
0028 #include "smb4khardwareinterface_p.h"
0029 
0030 #include <unistd.h>
0031 
0032 // Qt includes
0033 #include <QDebug>
0034 #include <QTest>
0035 #include <QString>
0036 #include <QDBusReply>
0037 
0038 // KDE includes
0039 #include <Solid/DeviceNotifier>
0040 #include <Solid/Device>
0041 #include <Solid/NetworkShare>
0042 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
0043 #include <KIOCore/KMountPoint>
0044 #endif
0045 
0046 Q_GLOBAL_STATIC(Smb4KHardwareInterfaceStatic, p);
0047 
0048 
0049 Smb4KHardwareInterface::Smb4KHardwareInterface(QObject *parent)
0050 : QObject(parent), d(new Smb4KHardwareInterfacePrivate)
0051 {
0052   //
0053   // Initialize some members
0054   // 
0055   d->networkSession = nullptr;
0056   d->systemOnline = false;
0057   d->fileDescriptor.setFileDescriptor(-1);
0058   
0059   //
0060   // Set up the DBUS interface
0061   // 
0062   d->dbusInterface.reset(new QDBusInterface("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus(), this));
0063   
0064   if (!d->dbusInterface->isValid())
0065   {
0066     d->dbusInterface.reset(new QDBusInterface("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", QDBusConnection::systemBus(), this));
0067   }
0068   
0069   //
0070   // Do the initial setup of the network configuration
0071   // 
0072   d->networkConfigManager.updateConfigurations();
0073   
0074   //
0075   // Connections
0076   // 
0077   connect(&d->networkConfigManager, SIGNAL(updateCompleted()), this, SLOT(slotNetworkConfigUpdated()));
0078   connect(&d->networkConfigManager, SIGNAL(onlineStateChanged(bool)), this, SLOT(slotOnlineStateChanged(bool)));
0079   
0080   connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), this, SLOT(slotDeviceAdded(QString)));
0081   connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), this, SLOT(slotDeviceRemoved(QString)));
0082 
0083 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
0084   startTimer(2000);
0085 #endif
0086 }
0087 
0088 
0089 Smb4KHardwareInterface::~Smb4KHardwareInterface()
0090 {
0091 }
0092 
0093 
0094 Smb4KHardwareInterface* Smb4KHardwareInterface::self()
0095 {
0096   return &p->instance;
0097 }
0098 
0099 
0100 bool Smb4KHardwareInterface::isOnline() const
0101 {
0102   if (d->networkSession)
0103   {
0104     return (d->networkSession->state() == QNetworkSession::Connected);
0105   }
0106   
0107   return false;
0108 }
0109 
0110 
0111 void Smb4KHardwareInterface::inhibit()
0112 {
0113   if (d->fileDescriptor.isValid())
0114   {
0115     return;
0116   }
0117   
0118   if (d->dbusInterface->isValid())
0119   {
0120     QVariantList args;
0121     args << QStringLiteral("shutdown:sleep");
0122     args << QStringLiteral("Smb4K");
0123     args << QStringLiteral("Mounting or unmounting in progress");
0124     args << QStringLiteral("delay");
0125     
0126     QDBusReply<QDBusUnixFileDescriptor> descriptor = d->dbusInterface->callWithArgumentList(QDBus::Block, QStringLiteral("Inhibit"), args);
0127     
0128     if (descriptor.isValid())
0129     {
0130       d->fileDescriptor = descriptor.value();
0131     }
0132   }
0133 }
0134 
0135 
0136 void Smb4KHardwareInterface::uninhibit()
0137 {
0138   if (!d->fileDescriptor.isValid())
0139   {
0140     return;
0141   }
0142   
0143   if (d->dbusInterface->isValid())
0144   {
0145     close(d->fileDescriptor.fileDescriptor());
0146     d->fileDescriptor.setFileDescriptor(-1);
0147   }
0148 }
0149 
0150 
0151 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
0152 // Using FreeBSD 11 with KF 5.27, Solid is not able to detect mounted shares.
0153 // Thus, we check here whether shares have been mounted or unmounted.
0154 // This is a hack and should be removed as soon as possible.
0155 void Smb4KHardwareInterface::timerEvent(QTimerEvent */*e*/)
0156 {
0157   KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::BasicInfoNeeded|KMountPoint::NeedMountOptions);
0158   QStringList mountPointList, alreadyMounted;
0159   
0160   for (const QExplicitlySharedDataPointer<KMountPoint> &mountPoint : mountPoints)
0161   {
0162     if (QString::compare(mountPoint->mountType(), "smbfs") == 0 || QString::compare(mountPoint->mountType(), "cifs") == 0)
0163     {
0164       mountPointList.append(mountPoint->mountPoint());
0165     }
0166   }
0167   
0168   QMutableStringListIterator it(mountPointList);
0169   
0170   while (it.hasNext())
0171   {
0172     QString mp = it.next();
0173     int index = -1;
0174     
0175     if ((index = d->mountPoints.indexOf(mp)) != -1)
0176     {
0177       d->mountPoints.removeAt(index);
0178       alreadyMounted.append(mp);
0179       it.remove();
0180     }
0181   }
0182   
0183   if (!d->mountPoints.isEmpty())
0184   {
0185     emit networkShareRemoved();
0186   }
0187   
0188   if (!mountPointList.isEmpty())
0189   {
0190     emit networkShareAdded();
0191   }
0192   
0193   d->mountPoints.clear();
0194   d->mountPoints.append(alreadyMounted);
0195   d->mountPoints.append(mountPointList);
0196 }
0197 #endif
0198 
0199 
0200 void Smb4KHardwareInterface::slotNetworkConfigUpdated()
0201 {
0202   if (d->networkConfigManager.isOnline())
0203   {
0204     //
0205     // Create a network session object and connect it to the stateChanged()
0206     // signal to monitor changes of the network connection.
0207     // 
0208     if (!d->networkSession)
0209     {
0210       d->networkSession = new QNetworkSession(d->networkConfigManager.defaultConfiguration(), this);
0211       connect(d->networkSession, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(slotConnectionStateChanged(QNetworkSession::State)));
0212     }
0213     
0214     //
0215     // Tell the program that the network session was initialized
0216     // 
0217     emit networkSessionInitialized();
0218     
0219     //
0220     // Check the state of the network session and emit the onlineStateChanged()
0221     // signal accordingly.
0222     // 
0223     if (d->networkSession->state() == QNetworkSession::Connected)
0224     {
0225       if (!d->systemOnline)
0226       {
0227         d->systemOnline = true;
0228         emit onlineStateChanged(true);
0229       }
0230     }
0231     else
0232     {
0233       if (d->systemOnline)
0234       {
0235         d->systemOnline = false;
0236         emit onlineStateChanged(false);
0237       }
0238     }
0239     
0240     //
0241     // Disconnect from the network configuration manager, because we now have our 
0242     // network session object
0243     // 
0244     disconnect(&d->networkConfigManager, SIGNAL(updateCompleted()), this, SLOT(slotNetworkConfigUpdated()));
0245     disconnect(&d->networkConfigManager, SIGNAL(onlineStateChanged(bool)), this, SLOT(slotOnlineStateChanged(bool)));
0246   }
0247   else
0248   {
0249     d->systemOnline = false;
0250     emit onlineStateChanged(false);
0251   }
0252 }
0253 
0254 
0255 void Smb4KHardwareInterface::slotOnlineStateChanged(bool on)
0256 {
0257   if (on && !d->networkSession)
0258   {
0259     d->networkConfigManager.updateConfigurations();
0260   }
0261 }
0262 
0263 
0264 void Smb4KHardwareInterface::slotConnectionStateChanged(QNetworkSession::State state)
0265 {
0266   if (state == QNetworkSession::Connected)
0267   {
0268     if (!d->systemOnline)
0269     {
0270       d->systemOnline = true;
0271       emit onlineStateChanged(true);
0272     }
0273   }
0274   else
0275   {
0276     if (d->systemOnline)
0277     {
0278       d->systemOnline = false;
0279       emit onlineStateChanged(false);
0280     }
0281   }
0282 }
0283 
0284 
0285 void Smb4KHardwareInterface::slotDeviceAdded(const QString& udi)
0286 {
0287   Solid::Device device(udi);
0288   
0289   if (device.isDeviceInterface(Solid::DeviceInterface::NetworkShare))
0290   {
0291     d->udis.append(udi);
0292     emit networkShareAdded();
0293   }
0294 }
0295 
0296 
0297 void Smb4KHardwareInterface::slotDeviceRemoved(const QString& udi)
0298 {
0299   Solid::Device device(udi);
0300   
0301   // For some reason, the device has no valid type at the moment (Frameworks 5.9, 
0302   // July 2015). Thus, we need the code in the else block for now. 
0303   if (device.isDeviceInterface(Solid::DeviceInterface::NetworkShare))
0304   {
0305     emit networkShareRemoved();
0306   }
0307   else
0308   {
0309     if (d->udis.contains(udi))
0310     {
0311       emit networkShareRemoved();
0312       d->udis.removeOne(udi);
0313     }
0314   }
0315 }
0316 
0317