File indexing completed on 2024-03-24 15:27:57

0001 /*  This file is part of kdebase/workspace/solid
0002     Copyright (C) 2005,2007 Will Stephenson <wstephenson@kde.org>
0003 
0004     Copyright (c) 2010 Klarälvdalens Datakonsult AB,
0005                        a KDAB Group company <info@kdab.com>
0006     Author: Kevin Ottens <kevin.ottens@kdab.com>
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Lesser General Public
0010     License as published by the Free Software Foundation; either
0011     version 2.1 of the License, or (at your option) version 3, or any
0012     later version accepted by the membership of KDE e.V. (or its
0013     successor approved by the membership of KDE e.V.), which shall
0014     act as a proxy defined in Section 6 of version 3 of the license.
0015 
0016     This library is distributed in the hope that it will be useful,
0017     but WITHOUT ANY WARRANTY; without even the implied warranty of
0018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0019     Lesser General Public License for more details.
0020 
0021     You should have received a copy of the GNU Lesser General Public
0022     License along with this library. If not, see <http://www.gnu.org/licenses/>.
0023 */
0024 
0025 #include "networkstatus.h"
0026 
0027 #include <QDBusServiceWatcher>
0028 #include <QMap>
0029 
0030 #include <kdebug.h>
0031 
0032 #include "clientadaptor.h"
0033 #include "serviceadaptor.h"
0034 
0035 #include "systemstatusinterface.h"
0036 
0037 #ifdef NM_BACKEND_ENABLED
0038 #include "networkmanagerstatus.h"
0039 #endif
0040 
0041 #include "wicdstatus.h"
0042 
0043 #include <kpluginfactory.h>
0044 #include "ntracknetworkstate.h"
0045 
0046 K_PLUGIN_FACTORY_WITH_JSON(NetworkStatusFactory,
0047                            "networkstatus.json",
0048                            registerPlugin<NetworkStatusModule>();)
0049 
0050 // INTERNALLY USED STRUCTS AND TYPEDEFS
0051 
0052 typedef QMap< QString, Network * > NetworkMap;
0053 
0054 class NetworkStatusModule::Private
0055 {
0056 public:
0057     Private() : status( Solid::Networking::Unknown ), backend( nullptr ), serviceWatcher( nullptr ),
0058                 backendAppearedWatcher( nullptr ), backendDisappearedWatcher ( nullptr )
0059     {
0060 
0061     }
0062     ~Private()
0063     {
0064 
0065     }
0066     NetworkMap networks;
0067     Solid::Networking::Status status;
0068     SystemStatusInterface *backend;
0069     QDBusServiceWatcher *serviceWatcher;
0070     QDBusServiceWatcher *backendAppearedWatcher;
0071     QDBusServiceWatcher *backendDisappearedWatcher;
0072 };
0073 
0074 // CTORS/DTORS
0075 
0076 NetworkStatusModule::NetworkStatusModule(QObject* parent, const QList<QVariant>&)
0077     : KDEDModule(parent), d( new Private )
0078 {
0079     new ClientAdaptor( this );
0080     new ServiceAdaptor( this );
0081 
0082 #ifdef HAVE_QNTRACK
0083     new NtrackNetworkState( this );
0084 #endif
0085 
0086     init();
0087 }
0088 
0089 NetworkStatusModule::~NetworkStatusModule()
0090 {
0091     Q_FOREACH ( Network * net, d->networks ) {
0092         delete net;
0093     }
0094 
0095     delete d;
0096 }
0097 
0098 // CLIENT INTERFACE
0099 
0100 int NetworkStatusModule::status()
0101 {
0102     kDebug( 1222 ) << " status: " << (int)d->status;
0103     return (int)d->status;
0104 }
0105 
0106 //protected:
0107 
0108 void NetworkStatusModule::updateStatus()
0109 {
0110     Solid::Networking::Status bestStatus = Solid::Networking::Unknown;
0111     const Solid::Networking::Status oldStatus = d->status;
0112 
0113     Q_FOREACH ( Network * net, d->networks ) {
0114         if ( net->status() > bestStatus )
0115             bestStatus = net->status();
0116     }
0117     d->status = bestStatus;
0118 
0119     if ( oldStatus != d->status ) {
0120         if (d->status == Solid::Networking::Connected) {
0121             QTimer::singleShot(2000, this, SLOT(delayedStatusChanged()));
0122         } else {
0123             emit statusChanged( (uint)d->status );
0124         }
0125     }
0126 }
0127 
0128 void NetworkStatusModule::delayedStatusChanged()
0129 {
0130     emit statusChanged( (uint)d->status );
0131 }
0132 
0133 void NetworkStatusModule::serviceUnregistered( const QString & name )
0134 {
0135     // unregister and delete any networks owned by a service that has just unregistered
0136     d->serviceWatcher->removeWatchedService( name );
0137     QMutableMapIterator<QString,Network*> it( d->networks );
0138     while ( it.hasNext() ) {
0139         it.next();
0140         if ( it.value()->service() == name ) {
0141             kDebug( 1222 ) << "Departing service " << name << " owned network " << it.value()->name() << ", removing it";
0142             Network * removedNet = it.value();
0143             it.remove();
0144             updateStatus();
0145             delete removedNet;
0146         }
0147     }
0148 }
0149 
0150 // SERVICE INTERFACE //
0151 
0152 QStringList NetworkStatusModule::networks()
0153 {
0154     if ( d->networks.count() ) {
0155       kDebug() << "Network status module is aware of " << d->networks.count() << " networks";
0156     } else {
0157       kDebug( 1222 ) << "Network status module is not aware of any networks";
0158     }
0159     return d->networks.keys();
0160 }
0161 
0162 void NetworkStatusModule::setNetworkStatus( const QString & networkName, int st )
0163 {
0164     kDebug( 1222 ) << networkName << ", " << st;
0165     Solid::Networking::Status changedStatus = (Solid::Networking::Status)st;
0166     if ( d->networks.contains( networkName ) ) {
0167         Network * net = d->networks[ networkName ];
0168         net->setStatus( changedStatus );
0169         updateStatus();
0170     } else {
0171       kDebug( 1222 ) << "  No network named '" << networkName << "' known.";
0172     }
0173 }
0174 
0175 void NetworkStatusModule::registerNetwork( const QString & networkName, int status, const QString & serviceName )
0176 {
0177     QDBusConnection dbus = QDBusConnection::sessionBus();
0178     QDBusConnectionInterface * sessionBus = dbus.interface();
0179     QString uniqueOwner = sessionBus->serviceOwner( serviceName ).value();
0180 
0181     kDebug( 1222 ) << networkName << ", with status " << status << " is owned by " << uniqueOwner;
0182 
0183     d->networks.insert( networkName, new Network( networkName, status, uniqueOwner ) );
0184 
0185     if ( d->serviceWatcher ) {
0186         d->serviceWatcher->addWatchedService( uniqueOwner );
0187     }
0188 
0189     updateStatus();
0190 }
0191 
0192 void NetworkStatusModule::unregisterNetwork( const QString & networkName )
0193 {
0194     if ( networkName != QLatin1String("SolidNetwork") ) {
0195         kDebug( 1222 ) << networkName << " unregistered.";
0196 
0197         if ( d->serviceWatcher ) {
0198             Network * net = d->networks.value( networkName );
0199             if ( net ) {
0200                 d->serviceWatcher->removeWatchedService( net->service() );
0201             }
0202         }
0203 
0204         d->networks.remove( networkName );
0205         updateStatus();
0206     }
0207 }
0208 
0209 void NetworkStatusModule::backendRegistered()
0210 {
0211     // we need to reset backend objects to make them connect to the appearing service.
0212     qDeleteAll(backends);
0213     backends.clear();
0214 
0215     delete d->backendAppearedWatcher;
0216     d->backendAppearedWatcher = nullptr;
0217 
0218     delete d->backendDisappearedWatcher;
0219     d->backendDisappearedWatcher = nullptr;
0220     init();
0221 }
0222 
0223 void NetworkStatusModule::backendUnregistered()
0224 {
0225     solidNetworkingStatusChanged(Solid::Networking::Unknown);
0226 }
0227 
0228 void NetworkStatusModule::init()
0229 {
0230     if (backends.isEmpty()) {
0231 #ifdef NM_BACKEND_ENABLED
0232         backends << new NetworkManagerStatus( this );
0233 #endif
0234         backends << new WicdStatus( this );
0235     }
0236 
0237     for ( int i = 0; i < backends.count(); i++ ) {
0238         if ( backends.value(i)->isSupported() ) {
0239             // select our backend...
0240             d->backend = backends.takeAt(i);
0241             // and delete the rest.
0242             qDeleteAll(backends);
0243             backends.clear();
0244             break;
0245         }
0246     }
0247 
0248     if (d->backendAppearedWatcher == nullptr) {
0249         d->backendAppearedWatcher = new QDBusServiceWatcher(this);
0250         d->backendAppearedWatcher->setConnection(QDBusConnection::systemBus());
0251         d->backendAppearedWatcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration);
0252     }
0253 
0254     if ( d->backend == nullptr ) {
0255         // if none found watch for all backends registration.
0256         for ( int i = 0; i < backends.count(); i++ ) {
0257             d->backendAppearedWatcher->addWatchedService(backends.value(i)->serviceName());
0258         }
0259         connect(d->backendAppearedWatcher, SIGNAL(serviceRegistered(QString)), SLOT(backendRegistered()));
0260         return;
0261     } else {
0262         // watch for the selected backend re-registration only.
0263         d->backendAppearedWatcher->addWatchedService(d->backend->serviceName());
0264         connect(d->backendAppearedWatcher, SIGNAL(serviceRegistered(QString)), SLOT(backendRegistered()));
0265 
0266         // watch for the selected bakend unregistration.
0267         if (d->backendDisappearedWatcher == nullptr) {
0268             d->backendDisappearedWatcher = new QDBusServiceWatcher(this);
0269             d->backendDisappearedWatcher->setConnection(QDBusConnection::systemBus());
0270             d->backendDisappearedWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
0271             d->backendDisappearedWatcher->addWatchedService(d->backend->serviceName());
0272             connect(d->backendDisappearedWatcher, SIGNAL(serviceUnregistered(QString)), SLOT(backendUnregistered()));
0273         }
0274 
0275         connect( d->backend, SIGNAL(statusChanged(Solid::Networking::Status)),
0276                  this, SLOT(solidNetworkingStatusChanged(Solid::Networking::Status)));
0277         Solid::Networking::Status status = d->backend->status();
0278         registerNetwork( QLatin1String("SolidNetwork"), status, QLatin1String("org.kde.kded5") );
0279     }
0280 
0281     d->serviceWatcher = new QDBusServiceWatcher(this);
0282     d->serviceWatcher->setConnection(QDBusConnection::sessionBus());
0283     d->serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
0284     connect(d->serviceWatcher, SIGNAL(serviceUnregistered(QString)), SLOT(serviceUnregistered(QString)));
0285 }
0286 
0287 void NetworkStatusModule::solidNetworkingStatusChanged( Solid::Networking::Status status )
0288 {
0289     kDebug( 1222 ) << "SolidNetwork changed status: " << status;
0290     setNetworkStatus( QLatin1String("SolidNetwork"), status );
0291 }
0292 
0293 #include "moc_networkstatus.cpp"
0294 #include "networkstatus.moc"