File indexing completed on 2024-05-05 05:36:55

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