File indexing completed on 2024-05-12 13:39:50

0001 /*
0002     SPDX-FileCopyrightText: 2013-2018 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 "networkmodel.h"
0008 #include "configuration.h"
0009 #include "networkmodelitem.h"
0010 #include "plasma_nm_libs.h"
0011 #include "uiutils.h"
0012 #include <QVector>
0013 #include <algorithm>
0014 
0015 #include <ModemManagerQt/Manager>
0016 
0017 #include <NetworkManagerQt/GenericDevice>
0018 #include <NetworkManagerQt/Settings>
0019 
0020 NetworkModel::NetworkModel(QObject *parent)
0021     : QAbstractListModel(parent)
0022 {
0023     QLoggingCategory::setFilterRules(QStringLiteral("plasma-nm.debug = false"));
0024 
0025     initialize();
0026 }
0027 
0028 NetworkModel::~NetworkModel() = default;
0029 
0030 QVariant NetworkModel::data(const QModelIndex &index, int role) const
0031 {
0032     const int row = index.row();
0033 
0034     if (row >= 0 && row < m_list.count()) {
0035         NetworkModelItem *item = m_list.itemAt(row);
0036 
0037         switch (role) {
0038         case ConnectionDetailsRole:
0039             return item->details();
0040         case ConnectionIconRole:
0041             return item->icon();
0042         case ConnectionPathRole:
0043             return item->connectionPath();
0044         case ConnectionStateRole:
0045             return item->connectionState();
0046         case DeviceName:
0047             return item->deviceName();
0048         case DevicePathRole:
0049             return item->devicePath();
0050         case DeviceStateRole:
0051             return item->deviceState();
0052         case DuplicateRole:
0053             return item->duplicate();
0054         case ItemUniqueNameRole:
0055             if (m_list.returnItems(NetworkItemsList::Name, item->name()).count() > 1) {
0056                 return item->originalName();
0057             } else {
0058                 return item->name();
0059             }
0060         case ItemTypeRole:
0061             return item->itemType();
0062         case LastUsedRole:
0063             return UiUtils::formatLastUsedDateRelative(item->timestamp());
0064         case LastUsedDateOnlyRole:
0065             return UiUtils::formatDateRelative(item->timestamp());
0066         case NameRole:
0067             return item->name();
0068         case SectionRole:
0069             return item->sectionType();
0070         case SignalRole:
0071             return item->signal();
0072         case SlaveRole:
0073             return item->slave();
0074         case SsidRole:
0075             return item->ssid();
0076         case SpecificPathRole:
0077             return item->specificPath();
0078         case SecurityTypeRole:
0079             return item->securityType();
0080         case SecurityTypeStringRole:
0081             return UiUtils::labelFromWirelessSecurity(item->securityType());
0082         case TimeStampRole:
0083             return item->timestamp();
0084         case TypeRole:
0085             return item->type();
0086         case UniRole:
0087             return item->uni();
0088         case UuidRole:
0089             return item->uuid();
0090         case VpnState:
0091             return item->vpnState();
0092         case VpnType:
0093             return item->vpnType();
0094         case RxBytesRole:
0095             return item->rxBytes();
0096         case TxBytesRole:
0097             return item->txBytes();
0098         case DelayModelUpdatesRole:
0099             return item->delayModelUpdates();
0100         case Qt::AccessibleDescriptionRole:
0101             return item->accessibleDescription();
0102         default:
0103             break;
0104         }
0105     }
0106 
0107     return {};
0108 }
0109 
0110 bool NetworkModel::setData(const QModelIndex &index, const QVariant &value, int role)
0111 {
0112     const int row = index.row();
0113     const bool delay = value.toBool();
0114 
0115     if (row >= 0 && row < m_list.count() && role == DelayModelUpdatesRole) {
0116         NetworkModelItem *item = m_list.itemAt(row);
0117         if (item->delayModelUpdates() != delay) {
0118             item->setDelayModelUpdates(delay);
0119             dataChanged(index, index, QVector<int>{DelayModelUpdatesRole});
0120             updateDelayModelUpdates();
0121             return true;
0122         }
0123     }
0124     return false;
0125 }
0126 
0127 int NetworkModel::rowCount(const QModelIndex &parent) const
0128 {
0129     Q_UNUSED(parent);
0130     return parent.isValid() ? 0 : m_list.count();
0131 }
0132 
0133 QHash<int, QByteArray> NetworkModel::roleNames() const
0134 {
0135     QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
0136     roles[ConnectionDetailsRole] = "ConnectionDetails";
0137     roles[ConnectionIconRole] = "ConnectionIcon";
0138     roles[ConnectionPathRole] = "ConnectionPath";
0139     roles[ConnectionStateRole] = "ConnectionState";
0140     roles[DeviceName] = "DeviceName";
0141     roles[DevicePathRole] = "DevicePath";
0142     roles[DeviceStateRole] = "DeviceState";
0143     roles[DuplicateRole] = "Duplicate";
0144     roles[ItemUniqueNameRole] = "ItemUniqueName";
0145     roles[ItemTypeRole] = "ItemType";
0146     roles[LastUsedRole] = "LastUsed";
0147     roles[LastUsedDateOnlyRole] = "LastUsedDateOnly";
0148     roles[NameRole] = "Name";
0149     roles[SectionRole] = "Section";
0150     roles[SignalRole] = "Signal";
0151     roles[SlaveRole] = "Slave";
0152     roles[SsidRole] = "Ssid";
0153     roles[SpecificPathRole] = "SpecificPath";
0154     roles[SecurityTypeRole] = "SecurityType";
0155     roles[SecurityTypeStringRole] = "SecurityTypeString";
0156     roles[TimeStampRole] = "TimeStamp";
0157     roles[TypeRole] = "Type";
0158     roles[Qt::AccessibleDescriptionRole] = "AccessibleDescription";
0159     roles[UniRole] = "Uni";
0160     roles[UuidRole] = "Uuid";
0161     roles[VpnState] = "VpnState";
0162     roles[VpnType] = "VpnType";
0163     roles[RxBytesRole] = "RxBytes";
0164     roles[TxBytesRole] = "TxBytes";
0165     roles[DelayModelUpdatesRole] = "DelayModelUpdates";
0166 
0167     return roles;
0168 }
0169 
0170 bool NetworkModel::delayModelUpdates() const
0171 {
0172     return m_delayModelUpdates;
0173 }
0174 
0175 void NetworkModel::updateDelayModelUpdates()
0176 {
0177     const QList<NetworkModelItem *> items = m_list.items();
0178     const bool delay = std::any_of(items.begin(), items.end(), [](NetworkModelItem *item) -> bool {
0179         return item->delayModelUpdates();
0180     });
0181     if (m_delayModelUpdates != delay) {
0182         m_delayModelUpdates = delay;
0183         Q_EMIT delayModelUpdatesChanged();
0184 
0185         if (!m_delayModelUpdates) {
0186             flushUpdateQueue();
0187         }
0188     }
0189 }
0190 
0191 void NetworkModel::flushUpdateQueue()
0192 {
0193     while (!m_updateQueue.isEmpty()) {
0194         QPair<NetworkModel::ModelChangeType, NetworkModelItem *> update = m_updateQueue.dequeue();
0195         if (update.first == ItemAdded) {
0196             insertItem(update.second);
0197         } else if (update.first == ItemRemoved) {
0198             removeItem(update.second);
0199         } else if (update.first == ItemPropertyChanged) {
0200             updateItem(update.second);
0201         }
0202     }
0203 }
0204 
0205 void NetworkModel::initialize()
0206 {
0207     // Initialize existing connections
0208     for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) {
0209         addConnection(connection);
0210     }
0211 
0212     // Initialize existing devices
0213     for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) {
0214         if (!dev->managed()) {
0215             continue;
0216         }
0217         // TODO implement loopback device in NetowrkManagerQt
0218         if (dev->interfaceName() == QLatin1String("lo")) {
0219             continue;
0220         }
0221         addDevice(dev);
0222     }
0223 
0224     // Initialize existing active connections
0225     for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) {
0226         addActiveConnection(active);
0227     }
0228 
0229     initializeSignals();
0230 }
0231 
0232 void NetworkModel::initializeSignals()
0233 {
0234     connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &NetworkModel::activeConnectionAdded, Qt::UniqueConnection);
0235     connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &NetworkModel::activeConnectionRemoved, Qt::UniqueConnection);
0236     connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &NetworkModel::connectionAdded, Qt::UniqueConnection);
0237     connect(NetworkManager::settingsNotifier(),
0238             &NetworkManager::SettingsNotifier::connectionRemoved,
0239             this,
0240             &NetworkModel::connectionRemoved,
0241             Qt::UniqueConnection);
0242     connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &NetworkModel::deviceAdded, Qt::UniqueConnection);
0243     connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &NetworkModel::deviceRemoved, Qt::UniqueConnection);
0244     connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &NetworkModel::statusChanged, Qt::UniqueConnection);
0245 }
0246 
0247 void NetworkModel::initializeSignals(const NetworkManager::ActiveConnection::Ptr &activeConnection)
0248 {
0249     if (activeConnection->vpn()) {
0250         NetworkManager::VpnConnection::Ptr vpnConnection = activeConnection.objectCast<NetworkManager::VpnConnection>();
0251         if (vpnConnection) {
0252             connect(vpnConnection.data(),
0253                     &NetworkManager::VpnConnection::stateChanged,
0254                     this,
0255                     &NetworkModel::activeVpnConnectionStateChanged,
0256                     Qt::UniqueConnection);
0257         }
0258     } else {
0259         connect(activeConnection.data(),
0260                 &NetworkManager::ActiveConnection::stateChanged,
0261                 this,
0262                 &NetworkModel::activeConnectionStateChanged,
0263                 Qt::UniqueConnection);
0264     }
0265 }
0266 
0267 void NetworkModel::initializeSignals(const NetworkManager::Connection::Ptr &connection)
0268 {
0269     connect(connection.data(), &NetworkManager::Connection::updated, this, &NetworkModel::connectionUpdated, Qt::UniqueConnection);
0270 }
0271 
0272 void NetworkModel::initializeSignals(const NetworkManager::Device::Ptr &device)
0273 {
0274     connect(device.data(), &NetworkManager::Device::availableConnectionAppeared, this, &NetworkModel::availableConnectionAppeared, Qt::UniqueConnection);
0275     connect(device.data(), &NetworkManager::Device::availableConnectionDisappeared, this, &NetworkModel::availableConnectionDisappeared, Qt::UniqueConnection);
0276     connect(device.data(), &NetworkManager::Device::ipV4ConfigChanged, this, &NetworkModel::ipConfigChanged, Qt::UniqueConnection);
0277     connect(device.data(), &NetworkManager::Device::ipV6ConfigChanged, this, &NetworkModel::ipConfigChanged, Qt::UniqueConnection);
0278     connect(device.data(), &NetworkManager::Device::ipInterfaceChanged, this, &NetworkModel::ipInterfaceChanged);
0279     connect(device.data(), &NetworkManager::Device::stateChanged, this, &NetworkModel::deviceStateChanged, Qt::UniqueConnection);
0280 
0281     auto deviceStatistics = device->deviceStatistics();
0282     connect(deviceStatistics.data(), &NetworkManager::DeviceStatistics::rxBytesChanged, this, [this, device](qulonglong rxBytes) {
0283         for (auto item : m_list.returnItems(NetworkItemsList::Device, device->uni())) {
0284             item->setRxBytes(rxBytes);
0285             updateItem(item);
0286         }
0287     });
0288     connect(deviceStatistics.data(), &NetworkManager::DeviceStatistics::txBytesChanged, this, [this, device](qulonglong txBytes) {
0289         for (auto item : m_list.returnItems(NetworkItemsList::Device, device->uni())) {
0290             item->setTxBytes(txBytes);
0291             updateItem(item);
0292         }
0293     });
0294 
0295     if (device->type() == NetworkManager::Device::Wifi) {
0296         NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast<NetworkManager::WirelessDevice>();
0297         connect(wifiDev.data(), &NetworkManager::WirelessDevice::networkAppeared, this, &NetworkModel::wirelessNetworkAppeared, Qt::UniqueConnection);
0298         connect(wifiDev.data(), &NetworkManager::WirelessDevice::networkDisappeared, this, &NetworkModel::wirelessNetworkDisappeared, Qt::UniqueConnection);
0299 
0300     } else if (device->type() == NetworkManager::Device::Modem) {
0301         ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(device->udi());
0302         if (modem) {
0303             if (modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) {
0304                 ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
0305                 if (modemNetwork) {
0306                     connect(modemNetwork.data(),
0307                             &ModemManager::Modem::signalQualityChanged,
0308                             this,
0309                             &NetworkModel::gsmNetworkSignalQualityChanged,
0310                             Qt::UniqueConnection);
0311                     connect(modemNetwork.data(),
0312                             &ModemManager::Modem::accessTechnologiesChanged,
0313                             this,
0314                             &NetworkModel::gsmNetworkAccessTechnologiesChanged,
0315                             Qt::UniqueConnection);
0316                     connect(modemNetwork.data(),
0317                             &ModemManager::Modem::currentModesChanged,
0318                             this,
0319                             &NetworkModel::gsmNetworkCurrentModesChanged,
0320                             Qt::UniqueConnection);
0321                 }
0322             }
0323         }
0324     }
0325 }
0326 
0327 void NetworkModel::initializeSignals(const NetworkManager::WirelessNetwork::Ptr &network)
0328 {
0329     connect(network.data(), &NetworkManager::WirelessNetwork::signalStrengthChanged, this, &NetworkModel::wirelessNetworkSignalChanged, Qt::UniqueConnection);
0330     connect(network.data(),
0331             &NetworkManager::WirelessNetwork::referenceAccessPointChanged,
0332             this,
0333             &NetworkModel::wirelessNetworkReferenceApChanged,
0334             Qt::UniqueConnection);
0335 }
0336 
0337 void NetworkModel::addActiveConnection(const NetworkManager::ActiveConnection::Ptr &activeConnection)
0338 {
0339     initializeSignals(activeConnection);
0340 
0341     NetworkManager::Device::Ptr device;
0342     NetworkManager::Connection::Ptr connection = activeConnection->connection();
0343 
0344     // Not necessary to have device for VPN connections
0345     if (activeConnection && !activeConnection->vpn() && !activeConnection->devices().isEmpty()) {
0346         device = NetworkManager::findNetworkInterface(activeConnection->devices().first());
0347     }
0348 
0349     // Check whether we have a base connection
0350     if (!m_list.contains(NetworkItemsList::Uuid, connection->uuid())) {
0351         // Active connection appeared before a base connection, so we have to add its base connection first
0352         addConnection(connection);
0353     }
0354 
0355     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::NetworkItemsList::Uuid, connection->uuid())) {
0356         if (((device && device->uni() == item->devicePath()) || item->devicePath().isEmpty()) || item->type() == NetworkManager::ConnectionSettings::Vpn) {
0357             item->setActiveConnectionPath(activeConnection->path());
0358             item->setConnectionState(activeConnection->state());
0359             if (activeConnection->vpn()) {
0360                 NetworkManager::VpnConnection::Ptr vpnConnection = activeConnection.objectCast<NetworkManager::VpnConnection>();
0361                 NetworkManager::VpnConnection::State state = vpnConnection->state();
0362                 if (state == NetworkManager::VpnConnection::Prepare //
0363                     || state == NetworkManager::VpnConnection::NeedAuth //
0364                     || state == NetworkManager::VpnConnection::Connecting //
0365                     || state == NetworkManager::VpnConnection::GettingIpConfig) {
0366                     item->setConnectionState(NetworkManager::ActiveConnection::Activating);
0367                 } else if (state == NetworkManager::VpnConnection::Activated) {
0368                     item->setConnectionState(NetworkManager::ActiveConnection::Activated);
0369                 } else {
0370                     item->setConnectionState(NetworkManager::ActiveConnection::Deactivated);
0371                 }
0372                 item->setVpnState(state);
0373             }
0374             item->invalidateDetails();
0375             qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": active connection state changed to " << item->connectionState();
0376 
0377             if (device && device->uni() == item->devicePath()) {
0378                 auto deviceStatistics = device->deviceStatistics();
0379                 if (deviceStatistics->refreshRateMs() != 0) {
0380                     item->setRxBytes(deviceStatistics->rxBytes());
0381                     item->setTxBytes(deviceStatistics->txBytes());
0382                 }
0383             }
0384         }
0385         updateItem(item);
0386     }
0387 }
0388 
0389 void NetworkModel::addAvailableConnection(const QString &connection, const NetworkManager::Device::Ptr &device)
0390 {
0391     if (!device) {
0392         return;
0393     }
0394 
0395     checkAndCreateDuplicate(connection, device->uni());
0396 
0397     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) {
0398         // The item is already associated with another device
0399         if (!device || !item->devicePath().isEmpty()) {
0400             continue;
0401         }
0402 
0403         if (device->ipInterfaceName().isEmpty()) {
0404             item->setDeviceName(device->interfaceName());
0405         } else {
0406             item->setDeviceName(device->ipInterfaceName());
0407         }
0408 
0409         item->setDevicePath(device->uni());
0410         item->setDeviceState(device->state());
0411         qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": device changed to " << item->devicePath();
0412         if (device->type() == NetworkManager::Device::Modem) {
0413             ModemManager::ModemDevice::Ptr modemDevice = ModemManager::findModemDevice(device->udi());
0414             if (modemDevice) {
0415                 ModemManager::Modem::Ptr modemInterface = modemDevice->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
0416                 if (modemInterface) {
0417                     item->setSignal(modemInterface->signalQuality().signal);
0418                     qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": signal changed to " << item->signal();
0419                 }
0420             }
0421         }
0422 
0423         if (item->type() == NetworkManager::ConnectionSettings::Wireless && item->mode() == NetworkManager::WirelessSetting::Infrastructure) {
0424             // Find an accesspoint which could be removed, because it will be merged with a connection
0425             for (NetworkModelItem *secondItem : m_list.returnItems(NetworkItemsList::Ssid, item->ssid())) {
0426                 if (secondItem->itemType() == NetworkModelItem::AvailableAccessPoint && secondItem->devicePath() == item->devicePath()) {
0427                     removeItem(secondItem);
0428                     qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Access point " << secondItem->name() << ": merged to " << item->name() << " connection";
0429                     break;
0430                 }
0431             }
0432 
0433             NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>();
0434             if (wifiDevice) {
0435                 NetworkManager::WirelessNetwork::Ptr wifiNetwork = wifiDevice->findNetwork(item->ssid());
0436                 if (wifiNetwork) {
0437                     updateFromWirelessNetwork(item, wifiNetwork, wifiDevice);
0438                 }
0439             }
0440         }
0441 
0442         updateItem(item);
0443         break;
0444     }
0445 }
0446 
0447 void NetworkModel::addConnection(const NetworkManager::Connection::Ptr &connection)
0448 {
0449     // Can't add a connection without name or uuid
0450     if (connection->name().isEmpty() || connection->uuid().isEmpty()) {
0451         return;
0452     }
0453 
0454     initializeSignals(connection);
0455 
0456     NetworkManager::ConnectionSettings::Ptr settings = connection->settings();
0457     NetworkManager::VpnSetting::Ptr vpnSetting;
0458     NetworkManager::WirelessSetting::Ptr wirelessSetting;
0459 
0460     if (settings->connectionType() == NetworkManager::ConnectionSettings::Vpn) {
0461         vpnSetting = settings->setting(NetworkManager::Setting::Vpn).dynamicCast<NetworkManager::VpnSetting>();
0462     } else if (settings->connectionType() == NetworkManager::ConnectionSettings::Wireless) {
0463         wirelessSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>();
0464     }
0465 
0466     // Check whether the connection is already in the model to avoid duplicates, but this shouldn't happen
0467     if (m_list.contains(NetworkItemsList::Connection, connection->path())) {
0468         return;
0469     }
0470 
0471     auto item = new NetworkModelItem();
0472     item->setConnectionPath(connection->path());
0473     item->setName(settings->id());
0474     item->setTimestamp(settings->timestamp());
0475     item->setType(settings->connectionType());
0476     item->setUuid(settings->uuid());
0477     item->setSlave(settings->isSlave());
0478 
0479     if (item->type() == NetworkManager::ConnectionSettings::Vpn) {
0480         item->setVpnType(vpnSetting->serviceType().section('.', -1));
0481     } else if (item->type() == NetworkManager::ConnectionSettings::Wireless) {
0482         item->setMode(wirelessSetting->mode());
0483         item->setSecurityType(NetworkManager::securityTypeFromConnectionSetting(settings));
0484         item->setSsid(QString::fromUtf8(wirelessSetting->ssid()));
0485     }
0486 
0487     item->invalidateDetails();
0488 
0489     insertItem(item);
0490     qCDebug(PLASMA_NM_LIBS_LOG) << "New connection" << item->name() << "added";
0491 }
0492 
0493 void NetworkModel::addDevice(const NetworkManager::Device::Ptr &device)
0494 {
0495     initializeSignals(device);
0496 
0497     if (device->type() == NetworkManager::Device::Wifi) {
0498         NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast<NetworkManager::WirelessDevice>();
0499         for (const NetworkManager::WirelessNetwork::Ptr &wifiNetwork : wifiDev->networks()) {
0500             addWirelessNetwork(wifiNetwork, wifiDev);
0501         }
0502     }
0503 
0504     for (const NetworkManager::Connection::Ptr &connection : device->availableConnections()) {
0505         addAvailableConnection(connection->path(), device);
0506     }
0507 }
0508 
0509 void NetworkModel::addWirelessNetwork(const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device)
0510 {
0511     initializeSignals(network);
0512 
0513     // Avoid duplicating entries in the model
0514     if (!Configuration::self().hotspotConnectionPath().isEmpty()) {
0515         NetworkManager::ActiveConnection::Ptr activeConnection = NetworkManager::findActiveConnection(Configuration::self().hotspotConnectionPath());
0516 
0517         // If we are trying to add an AP which is the one created by our hotspot, then we can skip this and don't add it twice
0518         if (activeConnection && activeConnection->specificObject() == network->referenceAccessPoint()->uni()) {
0519             return;
0520         }
0521     }
0522 
0523     // BUG: 386342
0524     // When creating a new hidden wireless network and attempting to connect to it, NM then later reports that AccessPoint appeared, but
0525     // it doesn't know its SSID from some reason, this also makes Wireless device to advertise a new available connection, which we later
0526     // attempt to merge with an AP, based on its SSID, but it doesn't find any, because we have AP with empty SSID. After this we get another
0527     // AccessPoint appeared signal, this time we know SSID, but we don't attempt any merging, because it's usually the other way around, thus
0528     // we need to attempt to merge it here with a connection we guess it's related to this new AP
0529     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Type, NetworkManager::ConnectionSettings::Wireless)) {
0530         if (item->itemType() != NetworkModelItem::AvailableConnection)
0531             continue;
0532 
0533         NetworkManager::ConnectionSettings::Ptr connectionSettings = NetworkManager::findConnection(item->connectionPath())->settings();
0534         if (connectionSettings && connectionSettings->connectionType() == NetworkManager::ConnectionSettings::Wireless) {
0535             NetworkManager::WirelessSetting::Ptr wirelessSetting =
0536                 connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>();
0537             if (QString::fromUtf8(wirelessSetting->ssid()) == network->ssid()) {
0538                 const QString bssid = NetworkManager::macAddressAsString(wirelessSetting->bssid());
0539                 const QString restrictedHw = NetworkManager::macAddressAsString(wirelessSetting->macAddress());
0540                 if ((bssid.isEmpty() || bssid == network->referenceAccessPoint()->hardwareAddress())
0541                     && (restrictedHw.isEmpty() || restrictedHw == device->hardwareAddress())) {
0542                     updateFromWirelessNetwork(item, network, device);
0543                     return;
0544                 }
0545             }
0546         }
0547     }
0548 
0549     NetworkManager::WirelessSetting::NetworkMode mode = NetworkManager::WirelessSetting::Infrastructure;
0550     NetworkManager::WirelessSecurityType securityType = NetworkManager::UnknownSecurity;
0551 
0552     NetworkManager::AccessPoint::Ptr ap = network->referenceAccessPoint();
0553     if (ap && (ap->capabilities().testFlag(NetworkManager::AccessPoint::Privacy) || ap->wpaFlags() || ap->rsnFlags())) {
0554         securityType = NetworkManager::findBestWirelessSecurity(device->wirelessCapabilities(),
0555                                                                 true,
0556                                                                 (device->mode() == NetworkManager::WirelessDevice::Adhoc),
0557                                                                 ap->capabilities(),
0558                                                                 ap->wpaFlags(),
0559                                                                 ap->rsnFlags());
0560         if (network->referenceAccessPoint()->mode() == NetworkManager::AccessPoint::Infra) {
0561             mode = NetworkManager::WirelessSetting::Infrastructure;
0562         } else if (network->referenceAccessPoint()->mode() == NetworkManager::AccessPoint::Adhoc) {
0563             mode = NetworkManager::WirelessSetting::Adhoc;
0564         } else if (network->referenceAccessPoint()->mode() == NetworkManager::AccessPoint::ApMode) {
0565             mode = NetworkManager::WirelessSetting::Ap;
0566         }
0567     }
0568 
0569     auto item = new NetworkModelItem();
0570     if (device->ipInterfaceName().isEmpty()) {
0571         item->setDeviceName(device->interfaceName());
0572     } else {
0573         item->setDeviceName(device->ipInterfaceName());
0574     }
0575     item->setDevicePath(device->uni());
0576     item->setMode(mode);
0577     item->setName(network->ssid());
0578     item->setSignal(network->signalStrength());
0579     item->setSpecificPath(network->referenceAccessPoint()->uni());
0580     item->setSsid(network->ssid());
0581     item->setType(NetworkManager::ConnectionSettings::Wireless);
0582     item->setSecurityType(securityType);
0583     item->invalidateDetails();
0584 
0585     insertItem(item);
0586     qCDebug(PLASMA_NM_LIBS_LOG) << "New wireless network" << item->name() << "added";
0587 }
0588 
0589 void NetworkModel::checkAndCreateDuplicate(const QString &connection, const QString &deviceUni)
0590 {
0591     bool createDuplicate = false;
0592     NetworkModelItem *originalItem = nullptr;
0593 
0594     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) {
0595         if (!item->duplicate()) {
0596             originalItem = item;
0597         }
0598 
0599         if (!item->duplicate() && item->itemType() == NetworkModelItem::AvailableConnection
0600             && (item->devicePath() != deviceUni && !item->devicePath().isEmpty())) {
0601             createDuplicate = true;
0602         }
0603     }
0604 
0605     if (createDuplicate) {
0606         auto duplicatedItem = new NetworkModelItem(originalItem);
0607         duplicatedItem->invalidateDetails();
0608 
0609         insertItem(duplicatedItem);
0610     }
0611 }
0612 
0613 void NetworkModel::onItemUpdated()
0614 {
0615     auto item = static_cast<NetworkModelItem *>(sender());
0616     if (item) {
0617         updateItem(item);
0618     }
0619 }
0620 
0621 void NetworkModel::setDeviceStatisticsRefreshRateMs(const QString &devicePath, uint refreshRate)
0622 {
0623     NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(devicePath);
0624 
0625     if (device) {
0626         device->deviceStatistics()->setRefreshRateMs(refreshRate);
0627     }
0628 }
0629 
0630 void NetworkModel::insertItem(NetworkModelItem *item)
0631 {
0632     if (m_delayModelUpdates) {
0633         m_updateQueue.enqueue(QPair<NetworkModel::ModelChangeType, NetworkModelItem *>(NetworkModel::ItemAdded, item));
0634         return;
0635     }
0636 
0637     const int index = m_list.count();
0638     beginInsertRows(QModelIndex(), index, index);
0639     m_list.insertItem(item);
0640     endInsertRows();
0641     updateDelayModelUpdates();
0642 }
0643 
0644 void NetworkModel::removeItem(NetworkModelItem *item)
0645 {
0646     if (m_delayModelUpdates) {
0647         m_updateQueue.enqueue(QPair<NetworkModel::ModelChangeType, NetworkModelItem *>(NetworkModel::ItemRemoved, item));
0648         return;
0649     }
0650 
0651     const int row = m_list.indexOf(item);
0652     if (row != -1) {
0653         beginRemoveRows(QModelIndex(), row, row);
0654         m_list.removeItem(item);
0655         item->deleteLater();
0656         endRemoveRows();
0657         updateDelayModelUpdates();
0658     }
0659 }
0660 
0661 void NetworkModel::updateItem(NetworkModelItem *item)
0662 {
0663     if (m_delayModelUpdates) {
0664         m_updateQueue.enqueue(QPair<NetworkModel::ModelChangeType, NetworkModelItem *>(NetworkModel::ItemPropertyChanged, item));
0665         return;
0666     }
0667 
0668     const int row = m_list.indexOf(item);
0669     if (row != -1) {
0670         item->invalidateDetails();
0671         QModelIndex index = createIndex(row, 0);
0672         Q_EMIT dataChanged(index, index, item->changedRoles());
0673         item->clearChangedRoles();
0674         updateDelayModelUpdates();
0675     }
0676 }
0677 
0678 void NetworkModel::accessPointSignalStrengthChanged(int signal)
0679 {
0680     auto apPtr = qobject_cast<NetworkManager::AccessPoint *>(sender());
0681     if (!apPtr) {
0682         return;
0683     }
0684 
0685     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, apPtr->ssid())) {
0686         if (item->specificPath() == apPtr->uni()) {
0687             item->setSignal(signal);
0688             updateItem(item);
0689             qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "AccessPoint " << item->name() << ": signal changed to " << item->signal();
0690         }
0691     }
0692 }
0693 
0694 void NetworkModel::activeConnectionAdded(const QString &activeConnection)
0695 {
0696     NetworkManager::ActiveConnection::Ptr activeCon = NetworkManager::findActiveConnection(activeConnection);
0697 
0698     if (activeCon) {
0699         addActiveConnection(activeCon);
0700     }
0701 }
0702 
0703 void NetworkModel::activeConnectionRemoved(const QString &activeConnection)
0704 {
0705     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::ActiveConnection, activeConnection)) {
0706         item->setActiveConnectionPath(QString());
0707         item->setConnectionState(NetworkManager::ActiveConnection::Deactivated);
0708         item->setVpnState(NetworkManager::VpnConnection::Disconnected);
0709         updateItem(item);
0710         qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": active connection removed";
0711     }
0712 }
0713 
0714 void NetworkModel::activeConnectionStateChanged(NetworkManager::ActiveConnection::State state)
0715 {
0716     auto activePtr = qobject_cast<NetworkManager::ActiveConnection *>(sender());
0717 
0718     if (!activePtr) {
0719         return;
0720     }
0721 
0722     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::ActiveConnection, activePtr->path())) {
0723         item->setConnectionState(state);
0724         updateItem(item);
0725         qCDebug(PLASMA_NM_LIBS_LOG) << "Item " << item->name() << ": active connection changed to " << item->connectionState();
0726     }
0727 }
0728 
0729 void NetworkModel::activeVpnConnectionStateChanged(NetworkManager::VpnConnection::State state, NetworkManager::VpnConnection::StateChangeReason reason)
0730 {
0731     Q_UNUSED(reason)
0732     auto activePtr = qobject_cast<NetworkManager::ActiveConnection *>(sender());
0733 
0734     if (!activePtr) {
0735         return;
0736     }
0737 
0738     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::ActiveConnection, activePtr->path())) {
0739         if (state == NetworkManager::VpnConnection::Prepare //
0740             || state == NetworkManager::VpnConnection::NeedAuth //
0741             || state == NetworkManager::VpnConnection::Connecting //
0742             || state == NetworkManager::VpnConnection::GettingIpConfig) {
0743             item->setConnectionState(NetworkManager::ActiveConnection::Activating);
0744         } else if (state == NetworkManager::VpnConnection::Activated) {
0745             item->setConnectionState(NetworkManager::ActiveConnection::Activated);
0746         } else {
0747             item->setConnectionState(NetworkManager::ActiveConnection::Deactivated);
0748         }
0749         item->setVpnState(state);
0750         updateItem(item);
0751         qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": active connection changed to " << item->connectionState();
0752     }
0753 }
0754 
0755 void NetworkModel::availableConnectionAppeared(const QString &connection)
0756 {
0757     NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast<NetworkManager::Device *>(sender())->uni());
0758     if (!device) {
0759         return;
0760     }
0761 
0762     addAvailableConnection(connection, device);
0763 }
0764 
0765 void NetworkModel::availableConnectionDisappeared(const QString &connection)
0766 {
0767     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) {
0768         bool available = false;
0769         const QString devicePath = item->devicePath();
0770         const QString specificPath = item->specificPath();
0771 
0772         // We have to check whether the connection is still available, because it might be
0773         // presented in the model for more devices and we don't want to remove it for all of them.
0774 
0775         // Check whether the device is still available
0776         NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(devicePath);
0777         if (device) {
0778             // Check whether the connection is still listed as available
0779             for (const NetworkManager::Connection::Ptr &connection : device->availableConnections()) {
0780                 if (connection->path() == item->connectionPath()) {
0781                     available = true;
0782                     break;
0783                 }
0784             }
0785         }
0786 
0787         if (!available) {
0788             item->setDeviceName(QString());
0789             item->setDevicePath(QString());
0790             item->setDeviceState(NetworkManager::Device::UnknownState);
0791             item->setSignal(0);
0792             item->setSpecificPath(QString());
0793             qCDebug(PLASMA_NM_LIBS_LOG) << "Item" << item->name() << "removed as available connection";
0794             // Check whether the connection is still available as an access point, this happens
0795             // when we change its properties, like ssid, bssid, security etc.
0796             if (item->type() == NetworkManager::ConnectionSettings::Wireless && !specificPath.isEmpty()) {
0797                 if (device && device->type() == NetworkManager::Device::Wifi) {
0798                     NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>();
0799                     if (wifiDevice) {
0800                         NetworkManager::AccessPoint::Ptr ap = wifiDevice->findAccessPoint(specificPath);
0801                         if (ap) {
0802                             NetworkManager::WirelessNetwork::Ptr network = wifiDevice->findNetwork(ap->ssid());
0803                             if (network) {
0804                                 addWirelessNetwork(network, wifiDevice);
0805                             }
0806                         }
0807                     }
0808                 }
0809             }
0810 
0811             if (item->duplicate()) {
0812                 removeItem(item);
0813                 qCDebug(PLASMA_NM_LIBS_LOG) << "Duplicate item" << item->name() << "removed completely";
0814             } else {
0815                 updateItem(item);
0816             }
0817         }
0818         available = false;
0819     }
0820 }
0821 
0822 void NetworkModel::connectionAdded(const QString &connection)
0823 {
0824     NetworkManager::Connection::Ptr newConnection = NetworkManager::findConnection(connection);
0825     if (newConnection) {
0826         addConnection(newConnection);
0827     }
0828 }
0829 
0830 void NetworkModel::connectionRemoved(const QString &connection)
0831 {
0832     bool remove = false;
0833     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) {
0834         // When the item type is wireless, we can remove only the connection and leave it as an available access point
0835         if (item->type() == NetworkManager::ConnectionSettings::Wireless && !item->devicePath().isEmpty()) {
0836             for (NetworkModelItem *secondItem : m_list.items()) {
0837                 // Remove it entirely when there is another connection with the same configuration and for the same device
0838                 // or it's a shared connection
0839                 if ((item->mode() != NetworkManager::WirelessSetting::Infrastructure)
0840                     || (item->connectionPath() != secondItem->connectionPath() //
0841                         && item->devicePath() == secondItem->devicePath() //
0842                         && item->mode() == secondItem->mode() //
0843                         && item->securityType() == secondItem->securityType() //
0844                         && item->ssid() == secondItem->ssid())) {
0845                     remove = true;
0846                     break;
0847                 }
0848             }
0849 
0850             if (!remove) {
0851                 item->setConnectionPath(QString());
0852                 item->setName(item->ssid());
0853                 item->setSlave(false);
0854                 item->setTimestamp(QDateTime());
0855                 item->setUuid(QString());
0856                 updateItem(item);
0857                 qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": connection removed";
0858             }
0859         } else {
0860             remove = true;
0861         }
0862 
0863         if (remove) {
0864             removeItem(item);
0865             qCDebug(PLASMA_NM_LIBS_LOG) << "Item" << item->name() << "removed completely";
0866         }
0867         remove = false;
0868     }
0869 }
0870 
0871 void NetworkModel::connectionUpdated()
0872 {
0873     auto connectionPtr = qobject_cast<NetworkManager::Connection *>(sender());
0874     if (!connectionPtr) {
0875         return;
0876     }
0877 
0878     NetworkManager::ConnectionSettings::Ptr settings = connectionPtr->settings();
0879     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connectionPtr->path())) {
0880         item->setConnectionPath(connectionPtr->path());
0881         item->setName(settings->id());
0882         item->setTimestamp(settings->timestamp());
0883         item->setType(settings->connectionType());
0884         item->setUuid(settings->uuid());
0885 
0886         if (item->type() == NetworkManager::ConnectionSettings::Wireless) {
0887             NetworkManager::WirelessSetting::Ptr wirelessSetting;
0888             wirelessSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>();
0889             item->setMode(wirelessSetting->mode());
0890             item->setSecurityType(NetworkManager::securityTypeFromConnectionSetting(settings));
0891             item->setSsid(QString::fromUtf8(wirelessSetting->ssid()));
0892             // TODO check whether BSSID has changed and update the wireless info
0893         }
0894 
0895         updateItem(item);
0896         qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": connection updated";
0897     }
0898 }
0899 
0900 void NetworkModel::deviceAdded(const QString &device)
0901 {
0902     NetworkManager::Device::Ptr dev = NetworkManager::findNetworkInterface(device);
0903     if (dev) {
0904         addDevice(dev);
0905     }
0906 }
0907 
0908 void NetworkModel::deviceRemoved(const QString &device)
0909 {
0910     // Make all items unavailable
0911     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device)) {
0912         availableConnectionDisappeared(item->connectionPath());
0913     }
0914 }
0915 
0916 void NetworkModel::deviceStateChanged(NetworkManager::Device::State state,
0917                                       NetworkManager::Device::State oldState,
0918                                       NetworkManager::Device::StateChangeReason reason)
0919 {
0920     Q_UNUSED(oldState);
0921     Q_UNUSED(reason);
0922 
0923     NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast<NetworkManager::Device *>(sender())->uni());
0924 
0925     if (!device) {
0926         return;
0927     }
0928 
0929     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) {
0930         item->setDeviceState(state);
0931         updateItem(item);
0932         // qCDebug(PLASMA_NM_LIBS_LOG) << "Item " << item->name() << ": device state changed to " << item->deviceState();
0933     }
0934 }
0935 
0936 void NetworkModel::gsmNetworkAccessTechnologiesChanged(QFlags<MMModemAccessTechnology> accessTechnologies)
0937 {
0938     Q_UNUSED(accessTechnologies);
0939     auto gsmNetwork = qobject_cast<ModemManager::Modem *>(sender());
0940     if (!gsmNetwork)
0941         return;
0942 
0943     for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) {
0944         if (dev->type() != NetworkManager::Device::Modem) {
0945             continue;
0946         }
0947 
0948         ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(dev->udi());
0949         if (!modem) {
0950             continue;
0951         }
0952 
0953         if (!modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) {
0954             continue;
0955         }
0956 
0957         ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
0958         if (!modemNetwork || modemNetwork->device() != gsmNetwork->device()) {
0959             continue;
0960         }
0961 
0962         // TODO store access technology internally?
0963         for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, dev->uni())) {
0964             updateItem(item);
0965         }
0966     }
0967 }
0968 
0969 void NetworkModel::gsmNetworkCurrentModesChanged()
0970 {
0971     auto gsmNetwork = qobject_cast<ModemManager::Modem *>(sender());
0972     if (!gsmNetwork) {
0973         return;
0974     }
0975 
0976     for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) {
0977         if (dev->type() != NetworkManager::Device::Modem)
0978             continue;
0979 
0980         ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(dev->udi());
0981         if (!modem) {
0982             continue;
0983         }
0984 
0985         if (!modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) {
0986             continue;
0987         }
0988 
0989         ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
0990         if (!modemNetwork || modemNetwork->device() != gsmNetwork->device()) {
0991             continue;
0992         }
0993 
0994         for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, dev->uni())) {
0995             updateItem(item);
0996         }
0997     }
0998 }
0999 
1000 void NetworkModel::gsmNetworkSignalQualityChanged(const ModemManager::SignalQualityPair &signalQuality)
1001 {
1002     auto gsmNetwork = qobject_cast<ModemManager::Modem *>(sender());
1003     if (!gsmNetwork) {
1004         return;
1005     }
1006 
1007     for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) {
1008         if (dev->type() != NetworkManager::Device::Modem) {
1009             continue;
1010         }
1011 
1012         ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(dev->udi());
1013         if (!modem) {
1014             continue;
1015         }
1016 
1017         if (!modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) {
1018             continue;
1019         }
1020 
1021         ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
1022         if (!modemNetwork || modemNetwork->device() != gsmNetwork->device()) {
1023             continue;
1024         }
1025 
1026         for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, dev->uni())) {
1027             item->setSignal(signalQuality.signal);
1028             updateItem(item);
1029         }
1030     }
1031 }
1032 
1033 void NetworkModel::ipConfigChanged()
1034 {
1035     NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast<NetworkManager::Device *>(sender())->uni());
1036 
1037     if (!device) {
1038         return;
1039     }
1040 
1041     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) {
1042         updateItem(item);
1043         // qCDebug(PLASMA_NM_LIBS_LOG) << "Item " << item->name() << ": device ipconfig changed";
1044     }
1045 }
1046 
1047 void NetworkModel::ipInterfaceChanged()
1048 {
1049     auto device = qobject_cast<NetworkManager::Device *>(sender());
1050     if (!device) {
1051         return;
1052     }
1053 
1054     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) {
1055         if (device->ipInterfaceName().isEmpty()) {
1056             item->setDeviceName(device->interfaceName());
1057         } else {
1058             item->setDeviceName(device->ipInterfaceName());
1059         }
1060     }
1061 }
1062 
1063 void NetworkModel::statusChanged(NetworkManager::Status status)
1064 {
1065     Q_UNUSED(status);
1066 
1067     qCDebug(PLASMA_NM_LIBS_LOG) << "NetworkManager state changed to" << status;
1068     // This has probably effect only for VPN connections
1069     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Type, NetworkManager::ConnectionSettings::Vpn)) {
1070         updateItem(item);
1071     }
1072 }
1073 
1074 void NetworkModel::wirelessNetworkAppeared(const QString &ssid)
1075 {
1076     NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast<NetworkManager::Device *>(sender())->uni());
1077     if (device && device->type() == NetworkManager::Device::Wifi) {
1078         NetworkManager::WirelessDevice::Ptr wirelessDevice = device.objectCast<NetworkManager::WirelessDevice>();
1079         NetworkManager::WirelessNetwork::Ptr network = wirelessDevice->findNetwork(ssid);
1080         addWirelessNetwork(network, wirelessDevice);
1081     }
1082 }
1083 
1084 void NetworkModel::wirelessNetworkDisappeared(const QString &ssid)
1085 {
1086     NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast<NetworkManager::Device *>(sender())->uni());
1087     if (!device) {
1088         return;
1089     }
1090 
1091     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, ssid, device->uni())) {
1092         // Remove the entire item, because it's only AP or it's a duplicated available connection
1093         if (item->itemType() == NetworkModelItem::AvailableAccessPoint || item->duplicate()) {
1094             removeItem(item);
1095             qCDebug(PLASMA_NM_LIBS_LOG) << "Wireless network" << item->name() << "removed completely";
1096             // Remove only AP and device from the item and leave it as an unavailable connection
1097         } else {
1098             if (item->mode() == NetworkManager::WirelessSetting::Infrastructure) {
1099                 item->setDeviceName(QString());
1100                 item->setDevicePath(QString());
1101                 item->setSpecificPath(QString());
1102             }
1103             item->setSignal(0);
1104             updateItem(item);
1105             qCDebug(PLASMA_NM_LIBS_LOG).nospace() << "Item " << item->name() << ": wireless network removed";
1106         }
1107     }
1108 }
1109 
1110 void NetworkModel::wirelessNetworkReferenceApChanged(const QString &accessPoint)
1111 {
1112     auto networkPtr = qobject_cast<NetworkManager::WirelessNetwork *>(sender());
1113 
1114     if (!networkPtr) {
1115         return;
1116     }
1117 
1118     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, networkPtr->ssid(), networkPtr->device())) {
1119         NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(item->connectionPath());
1120         if (!connection) {
1121             continue;
1122         }
1123 
1124         NetworkManager::WirelessSetting::Ptr wirelessSetting =
1125             connection->settings()->setting(NetworkManager::Setting::Wireless).staticCast<NetworkManager::WirelessSetting>();
1126         if (!wirelessSetting) {
1127             continue;
1128         }
1129 
1130         if (wirelessSetting->bssid().isEmpty()) {
1131             item->setSpecificPath(accessPoint);
1132             updateItem(item);
1133         }
1134     }
1135 }
1136 
1137 void NetworkModel::wirelessNetworkSignalChanged(int signal)
1138 {
1139     auto networkPtr = qobject_cast<NetworkManager::WirelessNetwork *>(sender());
1140     if (!networkPtr) {
1141         return;
1142     }
1143 
1144     for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, networkPtr->ssid(), networkPtr->device())) {
1145         if (item->specificPath() == networkPtr->referenceAccessPoint()->uni()) {
1146             item->setSignal(signal);
1147             updateItem(item);
1148             // qCDebug(PLASMA_NM_LIBS_LOG) << "Wireless network " << item->name() << ": signal changed to " << item->signal();
1149         }
1150     }
1151 }
1152 
1153 NetworkManager::WirelessSecurityType NetworkModel::alternativeWirelessSecurity(const NetworkManager::WirelessSecurityType type)
1154 {
1155     if (type == NetworkManager::WpaPsk) {
1156         return NetworkManager::Wpa2Psk;
1157     } else if (type == NetworkManager::WpaEap) {
1158         return NetworkManager::Wpa2Eap;
1159     } else if (type == NetworkManager::Wpa2Psk) {
1160         return NetworkManager::WpaPsk;
1161     } else if (type == NetworkManager::Wpa2Eap) {
1162         return NetworkManager::WpaEap;
1163     }
1164     return type;
1165 }
1166 
1167 void NetworkModel::updateFromWirelessNetwork(NetworkModelItem *item,
1168                                              const NetworkManager::WirelessNetwork::Ptr &network,
1169                                              const NetworkManager::WirelessDevice::Ptr &device)
1170 {
1171     NetworkManager::WirelessSecurityType securityType = NetworkManager::UnknownSecurity;
1172     NetworkManager::AccessPoint::Ptr ap = network->referenceAccessPoint();
1173     if (ap && ap->capabilities().testFlag(NetworkManager::AccessPoint::Privacy)) {
1174         securityType = NetworkManager::findBestWirelessSecurity(device->wirelessCapabilities(),
1175                                                                 true,
1176                                                                 (device->mode() == NetworkManager::WirelessDevice::Adhoc),
1177                                                                 ap->capabilities(),
1178                                                                 ap->wpaFlags(),
1179                                                                 ap->rsnFlags());
1180     }
1181 
1182     // Check whether the connection is associated with some concrete AP
1183     NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(item->connectionPath());
1184     if (connection) {
1185         NetworkManager::WirelessSetting::Ptr wirelessSetting =
1186             connection->settings()->setting(NetworkManager::Setting::Wireless).staticCast<NetworkManager::WirelessSetting>();
1187         if (wirelessSetting) {
1188             if (!wirelessSetting->bssid().isEmpty()) {
1189                 for (const NetworkManager::AccessPoint::Ptr &ap : network->accessPoints()) {
1190                     if (ap->hardwareAddress() == NetworkManager::macAddressAsString(wirelessSetting->bssid())) {
1191                         item->setSignal(ap->signalStrength());
1192                         item->setSpecificPath(ap->uni());
1193                         // We need to watch this AP for signal changes
1194                         connect(ap.data(),
1195                                 &NetworkManager::AccessPoint::signalStrengthChanged,
1196                                 this,
1197                                 &NetworkModel::accessPointSignalStrengthChanged,
1198                                 Qt::UniqueConnection);
1199                     }
1200                 }
1201             } else {
1202                 item->setSignal(network->signalStrength());
1203                 item->setSpecificPath(network->referenceAccessPoint()->uni());
1204             }
1205         }
1206     }
1207     item->setSecurityType(securityType);
1208     updateItem(item);
1209 }