File indexing completed on 2025-02-02 05:02:43

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "config-solid-extras.h"
0008 #include "networkstatus.h"
0009 #include "portalnetworkmonitor.h"
0010 
0011 #if HAVE_NM
0012 #include <NetworkManagerQt/Manager>
0013 #endif
0014 
0015 #include <QCoreApplication>
0016 #include <QDebug>
0017 
0018 namespace SolidExtras {
0019 class PortalNetworkMonitor : public QObject
0020 {
0021     Q_OBJECT
0022 public:
0023     static bool hasPortal();
0024     static NetworkStatus::State connectivity() { return instance()->m_connected; }
0025     static NetworkStatus::State metered() { return instance()->m_metered; }
0026     static PortalNetworkMonitor* instance();
0027 
0028 Q_SIGNALS:
0029     void connectivityChanged();
0030     void meteredChanged();
0031 
0032 private:
0033     PortalNetworkMonitor(QObject *parent = nullptr);
0034     void asyncUpdate();
0035     org::freedesktop::portal::NetworkMonitor m_iface;
0036     NetworkStatus::State m_connected = NetworkStatus::Unknown;
0037     NetworkStatus::State m_metered = NetworkStatus::Unknown;
0038 };
0039 }
0040 
0041 using namespace SolidExtras;
0042 
0043 PortalNetworkMonitor::PortalNetworkMonitor(QObject *parent)
0044     : QObject(parent)
0045     , m_iface(QLatin1StringView("org.freedesktop.portal.Desktop"), QLatin1StringView("/org/freedesktop/portal/desktop"), QDBusConnection::sessionBus())
0046 {
0047     connect(&m_iface, &org::freedesktop::portal::NetworkMonitor::changed, this, &PortalNetworkMonitor::asyncUpdate);
0048     if (m_iface.isValid()) {
0049         asyncUpdate();
0050     }
0051 }
0052 
0053 PortalNetworkMonitor* PortalNetworkMonitor::instance()
0054 {
0055     static PortalNetworkMonitor *s_instance = new PortalNetworkMonitor(QCoreApplication::instance());
0056     return s_instance;
0057 }
0058 
0059 bool SolidExtras::PortalNetworkMonitor::hasPortal()
0060 {
0061     return instance()->m_iface.isValid();
0062 }
0063 
0064 void PortalNetworkMonitor::asyncUpdate()
0065 {
0066     auto connectivityPendingReply = m_iface.GetConnectivity();
0067     auto connectivityWatcher = new QDBusPendingCallWatcher(connectivityPendingReply, this);
0068     connect(connectivityWatcher, &QDBusPendingCallWatcher::finished, this, [this](auto *watcher) {
0069         const QDBusPendingReply<unsigned int> reply(*watcher);
0070         if (reply.isValid() && ((reply.value() == 4) != (m_connected == NetworkStatus::Yes) || m_connected == NetworkStatus::Unknown)) {
0071             m_connected = (reply.value() == 4) ? NetworkStatus::Yes : NetworkStatus::No;
0072             Q_EMIT connectivityChanged();
0073         }
0074     });
0075 
0076     auto meteredPendingReply = m_iface.GetMetered();
0077     auto meteredWatcher = new QDBusPendingCallWatcher(meteredPendingReply, this);
0078     connect(meteredWatcher, &QDBusPendingCallWatcher::finished, this, [this](auto *watcher) {
0079         const QDBusPendingReply<bool> reply(*watcher);
0080         if (reply.isValid() && (reply.value() != (m_metered == NetworkStatus::Yes) || m_metered == NetworkStatus::Unknown)) {
0081             m_metered = reply.value() ? NetworkStatus::Yes : NetworkStatus::No;
0082             Q_EMIT meteredChanged();
0083         }
0084     });
0085 }
0086 
0087 
0088 NetworkStatus::NetworkStatus(QObject *parent)
0089     : QObject(parent)
0090 {
0091     qDebug() << "has portal:" << PortalNetworkMonitor::hasPortal();
0092     connect(PortalNetworkMonitor::instance(), &PortalNetworkMonitor::connectivityChanged, this, &NetworkStatus::connectivityChanged);
0093     connect(PortalNetworkMonitor::instance(), &PortalNetworkMonitor::meteredChanged, this, &NetworkStatus::meteredChanged);
0094 
0095 #if HAVE_NM
0096     if (!PortalNetworkMonitor::hasPortal()) {
0097         connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkStatus::connectivityChanged);
0098         connect(NetworkManager::notifier(), &NetworkManager::Notifier::meteredChanged, this, &NetworkStatus::meteredChanged);
0099     }
0100 #endif
0101 }
0102 
0103 NetworkStatus::State NetworkStatus::connectivity() const
0104 {
0105     if (PortalNetworkMonitor::hasPortal()) {
0106         return PortalNetworkMonitor::connectivity();
0107     }
0108 #if HAVE_NM
0109     switch (NetworkManager::connectivity()) {
0110         case NetworkManager::UnknownConnectivity:
0111             return Unknown;
0112         case NetworkManager::NoConnectivity:
0113         case NetworkManager::Portal:
0114         case NetworkManager::Limited:
0115             return No;
0116         case NetworkManager::Full:
0117             return Yes;
0118     }
0119     Q_UNREACHABLE();
0120 #endif
0121     return NetworkStatus::Unknown;
0122 }
0123 
0124 NetworkStatus::State NetworkStatus::metered() const
0125 {
0126     if (PortalNetworkMonitor::hasPortal()) {
0127         return PortalNetworkMonitor::metered();
0128     }
0129 #if HAVE_NM
0130     switch (NetworkManager::metered()) {
0131         case NetworkManager::Device::UnknownStatus:
0132             return Unknown;
0133         case NetworkManager::Device::GuessYes:
0134         case NetworkManager::Device::Yes:
0135             return Yes;
0136         case NetworkManager::Device::GuessNo:
0137         case NetworkManager::Device::No:
0138             return No;
0139     }
0140     Q_UNREACHABLE();
0141 #endif
0142     return NetworkStatus::Unknown;
0143 }
0144 
0145 #include "networkstatus_dbus.moc"