File indexing completed on 2024-07-21 07:58:12

0001 /*
0002     SPDX-FileCopyrightText: 2013 Jan Grulich <jgrulich@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "networkstatus.h"
0008 #include "uiutils.h"
0009 
0010 #include <QDBusConnection>
0011 #include <QDBusConnectionInterface>
0012 
0013 #include <NetworkManagerQt/ActiveConnection>
0014 #include <NetworkManagerQt/Connection>
0015 
0016 #include <KLocalizedString>
0017 
0018 NetworkStatus::SortedConnectionType NetworkStatus::connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type)
0019 {
0020     switch (type) {
0021     case NetworkManager::ConnectionSettings::Adsl:
0022         return NetworkStatus::NetworkStatus::Adsl;
0023         break;
0024     case NetworkManager::ConnectionSettings::Bluetooth:
0025         return NetworkStatus::Bluetooth;
0026         break;
0027     case NetworkManager::ConnectionSettings::Cdma:
0028         return NetworkStatus::Cdma;
0029         break;
0030     case NetworkManager::ConnectionSettings::Gsm:
0031         return NetworkStatus::Gsm;
0032         break;
0033     case NetworkManager::ConnectionSettings::Infiniband:
0034         return NetworkStatus::Infiniband;
0035         break;
0036     case NetworkManager::ConnectionSettings::OLPCMesh:
0037         return NetworkStatus::OLPCMesh;
0038         break;
0039     case NetworkManager::ConnectionSettings::Pppoe:
0040         return NetworkStatus::Pppoe;
0041         break;
0042     case NetworkManager::ConnectionSettings::Vpn:
0043         return NetworkStatus::Vpn;
0044         break;
0045     case NetworkManager::ConnectionSettings::Wired:
0046         return NetworkStatus::Wired;
0047         break;
0048     case NetworkManager::ConnectionSettings::Wireless:
0049         return NetworkStatus::Wireless;
0050         break;
0051     case NetworkManager::ConnectionSettings::WireGuard:
0052         return NetworkStatus::Wireguard;
0053         break;
0054     default:
0055         return NetworkStatus::Other;
0056         break;
0057     }
0058 }
0059 
0060 NetworkStatus::NetworkStatus(QObject *parent)
0061     : QObject(parent)
0062 {
0063     connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkStatus::changeActiveConnections);
0064     connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &NetworkStatus::connectivityChanged);
0065     connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &NetworkStatus::statusChanged);
0066     connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionsChanged, this, QOverload<>::of(&NetworkStatus::activeConnectionsChanged));
0067 
0068     activeConnectionsChanged();
0069     statusChanged(NetworkManager::status());
0070 
0071     QDBusPendingReply<uint> pendingReply = NetworkManager::checkConnectivity();
0072     auto callWatcher = new QDBusPendingCallWatcher(pendingReply);
0073     connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
0074         QDBusPendingReply<uint> reply = *watcher;
0075         if (reply.isValid()) {
0076             connectivityChanged((NetworkManager::Connectivity)reply.value());
0077         }
0078         watcher->deleteLater();
0079     });
0080 }
0081 
0082 NetworkStatus::~NetworkStatus() = default;
0083 
0084 QUrl NetworkStatus::networkCheckUrl()
0085 {
0086     return QUrl(QStringLiteral("http://networkcheck.kde.org/"));
0087 }
0088 
0089 QString NetworkStatus::activeConnections() const
0090 {
0091     return m_activeConnections;
0092 }
0093 
0094 QString NetworkStatus::networkStatus() const
0095 {
0096     return m_networkStatus;
0097 }
0098 
0099 NetworkManager::Connectivity NetworkStatus::connectivity() const
0100 {
0101     return NetworkManager::connectivity();
0102 }
0103 
0104 void NetworkStatus::activeConnectionsChanged()
0105 {
0106     for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) {
0107         connect(active.data(), &NetworkManager::ActiveConnection::default4Changed, this, &NetworkStatus::defaultChanged, Qt::UniqueConnection);
0108         connect(active.data(), &NetworkManager::ActiveConnection::default6Changed, this, &NetworkStatus::defaultChanged, Qt::UniqueConnection);
0109         connect(active.data(), &NetworkManager::ActiveConnection::stateChanged, this, &NetworkStatus::changeActiveConnections);
0110     }
0111 
0112     changeActiveConnections();
0113 }
0114 
0115 void NetworkStatus::defaultChanged()
0116 {
0117     statusChanged(NetworkManager::status());
0118 }
0119 
0120 void NetworkStatus::statusChanged(NetworkManager::Status status)
0121 {
0122     const auto oldNetworkStatus = m_networkStatus;
0123     switch (status) {
0124     case NetworkManager::ConnectedLinkLocal:
0125         m_networkStatus = i18nc("A network device is connected, but there is only link-local connectivity", "Connected");
0126         break;
0127     case NetworkManager::ConnectedSiteOnly:
0128         m_networkStatus = i18nc("A network device is connected, but there is only site-local connectivity", "Connected");
0129         break;
0130     case NetworkManager::Connected:
0131         m_networkStatus = i18nc("A network device is connected, with global network connectivity", "Connected");
0132         break;
0133     case NetworkManager::Asleep:
0134         m_networkStatus = i18nc("Networking is inactive and all devices are disabled", "Inactive");
0135         break;
0136     case NetworkManager::Disconnected:
0137         m_networkStatus = i18nc("There is no active network connection", "Disconnected");
0138         break;
0139     case NetworkManager::Disconnecting:
0140         m_networkStatus = i18nc("Network connections are being cleaned up", "Disconnecting");
0141         break;
0142     case NetworkManager::Connecting:
0143         m_networkStatus = i18nc("A network device is connecting to a network and there is no other available network connection", "Connecting");
0144         break;
0145     default:
0146         m_networkStatus = checkUnknownReason();
0147         break;
0148     }
0149 
0150     if (status == NetworkManager::ConnectedLinkLocal || status == NetworkManager::ConnectedSiteOnly || status == NetworkManager::Connected) {
0151         changeActiveConnections();
0152     } else if (m_activeConnections != m_networkStatus) {
0153         m_activeConnections = m_networkStatus;
0154         Q_EMIT activeConnectionsChanged(m_activeConnections);
0155     }
0156 }
0157 
0158 void NetworkStatus::changeActiveConnections()
0159 {
0160     if (NetworkManager::status() != NetworkManager::Connected && NetworkManager::status() != NetworkManager::ConnectedLinkLocal
0161         && NetworkManager::status() != NetworkManager::ConnectedSiteOnly) {
0162         return;
0163     }
0164 
0165     QString activeConnections;
0166     const QString format = QStringLiteral("%1: %2");
0167 
0168     QList<NetworkManager::ActiveConnection::Ptr> activeConnectionList = NetworkManager::activeConnections();
0169     std::sort(activeConnectionList.begin(),
0170               activeConnectionList.end(),
0171               [](const NetworkManager::ActiveConnection::Ptr &left, const NetworkManager::ActiveConnection::Ptr &right) {
0172                   return NetworkStatus::connectionTypeToSortedType(left->type()) < NetworkStatus::connectionTypeToSortedType(right->type());
0173               });
0174 
0175     for (const NetworkManager::ActiveConnection::Ptr &active : activeConnectionList) {
0176         if (!active->devices().isEmpty() && UiUtils::isConnectionTypeSupported(active->type())) {
0177             NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first());
0178             if (device
0179                 && ((device->type() != NetworkManager::Device::Generic && device->type() <= NetworkManager::Device::Team)
0180                     || device->type() == 29) // TODO: Change to WireGuard enum value when it is added
0181                 && device->interfaceName() != QLatin1String("lo")) { // TODO change to comparison with LocalHost enum value when it is added
0182                 bool connecting = false;
0183                 bool connected = false;
0184                 QString conType;
0185                 QString status;
0186                 NetworkManager::VpnConnection::Ptr vpnConnection;
0187 
0188                 if (active->vpn()) {
0189                     conType = i18n("VPN");
0190                     vpnConnection = active.objectCast<NetworkManager::VpnConnection>();
0191                 } else {
0192                     conType = UiUtils::interfaceTypeLabel(device->type(), device);
0193                 }
0194 
0195                 if (vpnConnection && active->vpn()) {
0196                     if (vpnConnection->state() >= NetworkManager::VpnConnection::Prepare
0197                         && vpnConnection->state() <= NetworkManager::VpnConnection::GettingIpConfig) {
0198                         connecting = true;
0199                     } else if (vpnConnection->state() == NetworkManager::VpnConnection::Activated) {
0200                         connected = true;
0201                     }
0202                 } else {
0203                     if (active->state() == NetworkManager::ActiveConnection::Activated) {
0204                         connected = true;
0205                     } else if (active->state() == NetworkManager::ActiveConnection::Activating) {
0206                         connecting = true;
0207                     }
0208                 }
0209 
0210                 if (active->type() == NetworkManager::ConnectionSettings::ConnectionType::WireGuard) {
0211                     conType = i18n("WireGuard");
0212                     connected = true;
0213                 }
0214 
0215                 NetworkManager::Connection::Ptr connection = active->connection();
0216                 if (connecting) {
0217                     status = i18n("Connecting to %1", connection->name());
0218                 } else if (connected) {
0219                     switch (NetworkManager::connectivity()) {
0220                     case NetworkManager::NoConnectivity:
0221                         status = i18n("Connected to %1 (no connectivity)", connection->name());
0222                         break;
0223                     case NetworkManager::Limited:
0224                         status = i18n("Connected to %1 (limited connectivity)", connection->name());
0225                         break;
0226                     case NetworkManager::Portal:
0227                         status = i18n("Connected to %1 (log in required)", connection->name());
0228                         break;
0229                     default:
0230                         status = i18n("Connected to %1", connection->name());
0231                         break;
0232                     }
0233                 }
0234 
0235                 if (!activeConnections.isEmpty()) {
0236                     activeConnections += QLatin1Char('\n');
0237                 }
0238                 activeConnections += format.arg(conType, status);
0239 
0240                 connect(connection.data(), &NetworkManager::Connection::updated, this, &NetworkStatus::changeActiveConnections, Qt::UniqueConnection);
0241             }
0242         }
0243     }
0244 
0245     if (m_activeConnections != activeConnections) {
0246         m_activeConnections = activeConnections;
0247         Q_EMIT activeConnectionsChanged(activeConnections);
0248     }
0249 }
0250 
0251 QString NetworkStatus::checkUnknownReason() const
0252 {
0253     // Check if NetworkManager is running.
0254     if (!QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral(NM_DBUS_INTERFACE))) {
0255         return i18n("NetworkManager not running");
0256     }
0257 
0258     // Check for compatible NetworkManager version.
0259     if (NetworkManager::compareVersion(0, 9, 8) < 0) {
0260         return i18n("NetworkManager 0.9.8 required, found %1.", NetworkManager::version());
0261     }
0262 
0263     return i18nc("global connection state", "Unknown");
0264 }
0265 
0266 #include "moc_networkstatus.cpp"