diff --git a/net-view/operation/private/nethotspotcontroller.cpp b/net-view/operation/private/nethotspotcontroller.cpp index c9dc6ac52..9cdae0e74 100644 --- a/net-view/operation/private/nethotspotcontroller.cpp +++ b/net-view/operation/private/nethotspotcontroller.cpp @@ -8,8 +8,10 @@ #include #include #include + #include #include +#include #include namespace dde { @@ -186,6 +188,14 @@ void NetHotspotController::updateConfig() config.insert(it.key(), it.value()); } QVariantMap typeMap = config["802-11-wireless"].value(); + // ssid 在 NM 侧是原始字节(可能 GBK 编码),转为 UTF-8 字符串后交给 UI 显示, + // 避免 QML 按 UTF-8 直读 QByteArray 产生乱码(参考 nm_utils_ssid_to_utf8 语义) + QByteArray rawSsid; + if (typeMap.contains("ssid")) { + rawSsid = typeMap.value("ssid").toByteArray(); + if (!rawSsid.isEmpty()) + typeMap["ssid"] = ssidToUtf8(rawSsid); + } typeMap.insert("optionalDevice", m_optionalDevice); config["802-11-wireless"] = typeMap; m_config = config; diff --git a/net-view/operation/private/netmanagerthreadprivate.cpp b/net-view/operation/private/netmanagerthreadprivate.cpp index 15c527f9c..53d18977e 100644 --- a/net-view/operation/private/netmanagerthreadprivate.cpp +++ b/net-view/operation/private/netmanagerthreadprivate.cpp @@ -20,6 +20,8 @@ #include "private/vpnparameterschecker.h" #include "wireddevice.h" #include "wirelessdevice.h" +#include + #include #include @@ -717,7 +719,7 @@ void NetManagerThreadPrivate::doConnectHidden(const QString &id, const QString & if (!wirelessDevice) return; NetWirelessConnect wConnect(wirelessDevice, nullptr, this); - wConnect.setSsid(ssid); + wConnect.setRawSsid(ssid.toUtf8()); wConnect.initConnection(); wConnect.connectNetwork(); } @@ -779,7 +781,7 @@ void NetManagerThreadPrivate::doConnectWireless(const QString &id, const QVarian return; } NetWirelessConnect wConnect(wirelessDevice, ap, this); - wConnect.setSsid(ap->ssid()); + wConnect.setRawSsid(ap->rawSsid()); wConnect.initConnection(); QString secret = wConnect.needSecrets(); @@ -954,9 +956,8 @@ void NetManagerThreadPrivate::doConnectOrInfo(const QString &id, NetType::NetIte ConnectionSettings::Ptr settings; for (const NetworkManager::Connection::Ptr &con : netDevice->availableConnections()) { NetworkManager::WirelessSetting::Ptr wSetting = con->settings()->setting(NetworkManager::Setting::SettingType::Wireless).staticCast(); - if (wSetting->ssid() != ap->ssid()) { + if (!ssidBytesMatch(wSetting->ssid(), ap->rawSsid(), ap->ssid())) continue; - } settings = con->settings(); WirelessSecuritySetting::Ptr const sSetting = settings->setting(Setting::SettingType::WirelessSecurity).staticCast(); @@ -980,7 +981,7 @@ void NetManagerThreadPrivate::doConnectOrInfo(const QString &id, NetType::NetIte NetworkManager::ConnectionSettings::Ptr settings = NetworkManager::ConnectionSettings::Ptr(new ConnectionSettings(ConnectionSettings::Wireless)); settings->setId(ap->ssid()); NetworkManager::WirelessSetting::Ptr wSetting = settings->setting(Setting::SettingType::Wireless).staticCast(); - wSetting->setSsid(ap->ssid().toUtf8()); + wSetting->setSsid(ssidForSave(ap->rawSsid(), ap->ssid())); wSetting->setInitialized(true); WirelessSecuritySetting::Ptr wsSetting = settings->setting(Setting::WirelessSecurity).dynamicCast(); switch (keyMgmt) { @@ -1186,9 +1187,8 @@ void NetManagerThreadPrivate::doGetConnectInfo(const QString &id, NetType::NetIt ConnectionSettings::Ptr settings; for (const NetworkManager::Connection::Ptr &con : netDevice->availableConnections()) { NetworkManager::WirelessSetting::Ptr wSetting = con->settings()->setting(NetworkManager::Setting::SettingType::Wireless).staticCast(); - if (wSetting->ssid() != ap->ssid()) { + if (!ssidBytesMatch(wSetting->ssid(), ap->rawSsid(), ap->ssid())) continue; - } settings = con->settings(); WirelessSecuritySetting::Ptr sSetting = settings->setting(Setting::SettingType::WirelessSecurity).staticCast(); @@ -1283,7 +1283,7 @@ void NetManagerThreadPrivate::doGetConnectInfo(const QString &id, NetType::NetIt NetworkManager::ConnectionSettings::Ptr settings = NetworkManager::ConnectionSettings::Ptr(new ConnectionSettings(ConnectionSettings::Wireless)); settings->setId(ap->ssid()); NetworkManager::WirelessSetting::Ptr wSetting = settings->setting(Setting::SettingType::Wireless).staticCast(); - wSetting->setSsid(ap->ssid().toUtf8()); + wSetting->setSsid(ssidForSave(ap->rawSsid(), ap->ssid())); wSetting->setHidden(hidden); wSetting->setInitialized(true); WirelessSecuritySetting::Ptr wsSetting = settings->setting(Setting::WirelessSecurity).dynamicCast(); @@ -2176,7 +2176,8 @@ void NetManagerThreadPrivate::addNetwork(const NetworkDeviceBase *device, QList< NetworkManager::WirelessSetting::Ptr wirelessSetting = connection->settings()->setting(NetworkManager::Setting::SettingType::Wireless).dynamicCast(); if (wirelessSetting.isNull()) return false; - return wirelessSetting->ssid() == ap->ssid() && !connection->isUnsaved(); + return ssidBytesMatch(wirelessSetting->ssid(), ap->rawSsid(), ap->ssid()) + && !connection->isUnsaved(); }); item->updatehasConnection(itConnection != connections.end()); Q_EMIT itemAdded(device->path(), item); @@ -2290,7 +2291,8 @@ void NetManagerThreadPrivate::onAvailableConnectionsChanged() NetworkManager::WirelessSetting::Ptr wirelessSetting = connection->settings()->setting(NetworkManager::Setting::SettingType::Wireless).dynamicCast(); if (wirelessSetting.isNull()) return false; - return wirelessSetting->ssid() == tmpAp->ssid() && !connection->isUnsaved(); + return ssidBytesMatch(wirelessSetting->ssid(), tmpAp->rawSsid(), tmpAp->ssid()) + && !connection->isUnsaved(); }); if (itConnection != connections.end()) { availableAccessPoints.append(apID(tmpAp)); @@ -2811,7 +2813,8 @@ void NetManagerThreadPrivate::updateHiddenNetworkConfig(WirelessDevice *wireless NetworkManager::WirelessSecuritySetting::Ptr const wsSetting = connSettings->setting(NetworkManager::Setting::SettingType::WirelessSecurity).staticCast(); if ((wsSetting) && NetworkManager::WirelessSecuritySetting::KeyMgmt::Unknown == wsSetting->keyMgmt()) { for (auto *ap : wireless->accessPointItems()) { - if (ap->ssid() == wSetting->ssid() && ap->secured() && ap->strength() > 0) { + if (ssidBytesMatch(wSetting->ssid(), ap->rawSsid(), ap->ssid()) + && ap->secured() && ap->strength() > 0) { handleAccessPointSecure(ap); } } @@ -2957,7 +2960,7 @@ void NetManagerThreadPrivate::handleAccessPointSecure(AccessPoints *accessPoint) return; NetWirelessConnect wConnect(dynamic_cast(*it), accessPoint, this); - wConnect.setSsid(accessPoint->ssid()); + wConnect.setRawSsid(accessPoint->rawSsid()); wConnect.initConnection(); QVariantMap param; param.insert("secrets", { wConnect.needSecrets() }); @@ -3057,7 +3060,7 @@ void NetManagerThreadPrivate::onPortalDetected(const QString &portalUrl) dde::network::WirelessDevice *wirelessDevice = static_cast(networkDevice); // 找到无线连接对应那个网络 for (dde::network::AccessPoints *ap : wirelessDevice->accessPointItems()) { - if (ap->ssid() != wirelessSetting->ssid()) + if (!ssidBytesMatch(wirelessSetting->ssid(), ap->rawSsid(), ap->ssid())) continue; Q_EMIT dataChanged(DataChanged::portalUrlChanged, apID(ap), portalUrl); diff --git a/net-view/operation/private/netwirelessconnect.cpp b/net-view/operation/private/netwirelessconnect.cpp index de9a903fa..c553a8766 100644 --- a/net-view/operation/private/netwirelessconnect.cpp +++ b/net-view/operation/private/netwirelessconnect.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,6 +6,7 @@ #include "configsetting.h" #include "nmnetworkmanager.h" +#include #include #include @@ -38,9 +39,9 @@ NetWirelessConnect::NetWirelessConnect(dde::network::WirelessDevice *device, dde NetWirelessConnect::~NetWirelessConnect() = default; -void NetWirelessConnect::setSsid(const QString &ssid) +void NetWirelessConnect::setRawSsid(const QByteArray &rawSsid) { - m_ssid = ssid; + m_rawSsid = rawSsid; m_connectionSettings.clear(); } @@ -187,12 +188,12 @@ bool NetWirelessConnect::initConnection() if (m_accessPoint) { NetworkManager::Connection::Ptr conn; for (const ActiveConnection::Ptr &con : NetworkManager::activeConnections()) { - if (con->type() != ConnectionSettings::ConnectionType::Wireless || con->id() != m_ssid) + if (con->type() != ConnectionSettings::ConnectionType::Wireless) continue; NetworkManager::ConnectionSettings::Ptr connSettings = con->connection()->settings(); NetworkManager::WirelessSetting::Ptr wSetting = connSettings->setting(NetworkManager::Setting::SettingType::Wireless).staticCast(); - if (wSetting.isNull()) + if (wSetting.isNull() || wSetting->ssid() != m_rawSsid) continue; QString settingMacAddress = wSetting->macAddress().toHex().toUpper(); @@ -208,7 +209,7 @@ bool NetWirelessConnect::initConnection() // 如果找到的conn是空的,当前的setting也需要重置 m_connectionSettings.reset(); for (auto item : m_device->items()) { - if (item->connection()->ssid() != m_ssid) + if (item->connection()->ssid() != m_rawSsid) continue; QString uuid = item->connection()->uuid(); @@ -237,11 +238,12 @@ bool NetWirelessConnect::initConnection() uuid.replace(24, QString::number(second).length(), QString::number(second)); } m_connectionSettings->setUuid(uuid); - m_connectionSettings->setId(m_ssid); + QString ssid = ssidToUtf8(m_rawSsid); + m_connectionSettings->setId(ssid); if (!m_accessPoint) { m_connectionSettings->setting(Setting::SettingType::Wireless).staticCast()->setHidden(true); } - qCInfo(DNC) << "Wireless connect init, create connect: ssid: " << m_ssid << ", uuid: " << uuid << ", access point: " << m_accessPoint; + qCInfo(DNC) << "Wireless connect init, create connect: ssid: " << ssid << ", uuid: " << uuid << ", access point: " << m_accessPoint; if (m_accessPoint) { WirelessSecuritySetting::Ptr wsSetting = m_connectionSettings->setting(Setting::WirelessSecurity).dynamicCast(); WirelessSecuritySetting::KeyMgmt keyMgmt = getKeyMgmtByAp(m_accessPoint); @@ -261,7 +263,9 @@ bool NetWirelessConnect::initConnection() } } WirelessSetting::Ptr const wirelessSetting = m_connectionSettings->setting(Setting::Wireless).dynamicCast(); - wirelessSetting->setSsid(m_ssid.toUtf8()); + // 优先保存 AP 原始字节(与 NM 字节匹配一致),rawSsid 为空(如隐藏网络)时回退 UTF-8 + const QByteArray rawSsid = m_accessPoint ? m_accessPoint->rawSsid() : QByteArray(); + wirelessSetting->setSsid(ssidForSave(rawSsid, m_rawSsid)); wirelessSetting->setInitialized(true); m_needUpdate = true; if (m_needIdentify) { diff --git a/net-view/operation/private/netwirelessconnect.h b/net-view/operation/private/netwirelessconnect.h index de3deb91e..253a6dc1f 100644 --- a/net-view/operation/private/netwirelessconnect.h +++ b/net-view/operation/private/netwirelessconnect.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -27,7 +27,7 @@ class NetWirelessConnect : public QObject explicit NetWirelessConnect(dde::network::WirelessDevice *device, dde::network::AccessPoints *ap, QObject *parent = nullptr); ~NetWirelessConnect() Q_DECL_OVERRIDE; - void setSsid(const QString &ssid); + void setRawSsid(const QByteArray &rawSsid); bool initConnection(); bool passwordIsValid(const QString &password); @@ -53,7 +53,7 @@ public Q_SLOTS: private: dde::network::WirelessDevice *m_device; dde::network::AccessPoints *m_accessPoint; - QString m_ssid; + QByteArray m_rawSsid; bool m_needUpdate; bool m_needIdentify; diff --git a/src/impl/netinterface.h b/src/impl/netinterface.h index 4f208b6bb..21fe070c1 100644 --- a/src/impl/netinterface.h +++ b/src/impl/netinterface.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -189,6 +189,7 @@ class AccessPointProxy : public QObject virtual ConnectionStatus status() const = 0; // 当前网络的连接状态 virtual bool hidden() const = 0; // 是否为隐藏网络 virtual bool isWlan6() const = 0; + virtual QByteArray rawSsid() const { return QByteArray(); } // 网络SSID原始字节,用于与NM侧连接字节精确匹配 Q_SIGNALS: void strengthChanged(const int); // 当前信号强度变化 diff --git a/src/impl/networkmanager/accesspointproxynm.cpp b/src/impl/networkmanager/accesspointproxynm.cpp index 06363fd7d..c8ff1f8aa 100644 --- a/src/impl/networkmanager/accesspointproxynm.cpp +++ b/src/impl/networkmanager/accesspointproxynm.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -57,9 +57,21 @@ bool AccessPointProxyNM::contains(const QString &uni) const QString AccessPointProxyNM::ssid() const { + // 用原始字节做 locale 感知解码(对齐 nm_utils_ssid_to_utf8),避免依赖上游 qt6 的 fromUtf8 + const QByteArray raw = rawSsid(); + if (!raw.isEmpty()) + return ssidToUtf8(raw); return m_network->ssid(); } +QByteArray AccessPointProxyNM::rawSsid() const +{ + if (m_network.isNull() || m_network->referenceAccessPoint().isNull()) + return QByteArray(); + + return m_network->referenceAccessPoint()->rawSsid(); +} + int AccessPointProxyNM::strength() const { return m_strength; @@ -134,7 +146,7 @@ void AccessPointProxyNM::initState() if (wirelessSetting.isNull()) return; - if (wirelessSetting->ssid() != m_network->ssid()) + if (!ssidBytesMatch(wirelessSetting->ssid(), rawSsid(), ssid())) return; updateStatus(convertStateFromNetworkManager(activeConnection->state())); @@ -180,8 +192,7 @@ void AccessPointProxyNM::updateHiddenInfo() NetworkManager::WirelessSetting::Ptr wirelessSetting = connection->settings()->setting(NetworkManager::Setting::SettingType::Wireless).dynamicCast(); if (wirelessSetting.isNull()) return false; - - return wirelessSetting->ssid() == m_network->ssid(); + return ssidBytesMatch(wirelessSetting->ssid(), rawSsid(), ssid()); }); // 如果没有找到连接,就是非隐藏网络 if (itConnection == connections.end()) diff --git a/src/impl/networkmanager/accesspointproxynm.h b/src/impl/networkmanager/accesspointproxynm.h index aa06dfaad..fc6a43d28 100644 --- a/src/impl/networkmanager/accesspointproxynm.h +++ b/src/impl/networkmanager/accesspointproxynm.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -39,6 +39,7 @@ class AccessPointProxyNM : public AccessPointProxy ConnectionStatus status() const override; bool hidden() const override; bool isWlan6() const override; + QByteArray rawSsid() const override; void updateStrengthFromActiveAp(int strength); private: diff --git a/src/impl/networkmanager/devicemanagerrealize.cpp b/src/impl/networkmanager/devicemanagerrealize.cpp index 22cd90b9b..4e0d127dc 100644 --- a/src/impl/networkmanager/devicemanagerrealize.cpp +++ b/src/impl/networkmanager/devicemanagerrealize.cpp @@ -761,7 +761,7 @@ void WirelessDeviceManagerRealize::connectNetwork(const AccessPoints *accessPoin if (wSetting.isNull()) return false; - return wSetting->ssid() == accessPoint->ssid(); + return ssidBytesMatch(wSetting->ssid(), accessPoint->rawSsid(), accessPoint->ssid()); }); if (itConnection == availableConnections.end()) { @@ -780,7 +780,7 @@ void WirelessDeviceManagerRealize::connectNetwork(const AccessPoints *accessPoin if (!configMacAddress.isEmpty() && configMacAddress != realHwAdr().remove(":")) continue; - if (wSetting->ssid() == accessPoint->ssid()) { + if (ssidBytesMatch(wSetting->ssid(), accessPoint->rawSsid(), accessPoint->ssid())) { currentConnection = connection; break; } @@ -817,7 +817,7 @@ void WirelessDeviceManagerRealize::connectNetwork(const AccessPoints *accessPoin } NetworkManager::WirelessSetting::Ptr wirelessSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); - wirelessSetting->setSsid(accessPoint->ssid().toUtf8()); + wirelessSetting->setSsid(ssidForSave(accessPoint->rawSsid(), accessPoint->ssid())); QString macAddress = m_device->permanentHardwareAddress(); macAddress.remove(":"); wirelessSetting->setMacAddress(QByteArray::fromHex(macAddress.toUtf8())); @@ -1019,7 +1019,7 @@ AccessPointProxyNM *WirelessDeviceManagerRealize::findAccessPoints(NetworkManage return nullptr; const auto itAccessPoint = std::find_if(m_accessPointInfos.cbegin(), m_accessPointInfos.cend(), [wirelessSetting](AccessPointInfo *accessPoint) { - return accessPoint->accessPoint()->ssid() == wirelessSetting->ssid(); + return ssidBytesMatch(wirelessSetting->ssid(), accessPoint->accessPoint()->rawSsid(), accessPoint->accessPoint()->ssid()); }); return itAccessPoint == m_accessPointInfos.cend() ? nullptr : (*itAccessPoint)->proxy(); @@ -1047,9 +1047,7 @@ void WirelessDeviceManagerRealize::onStateChanged(NetworkManager::ActiveConnecti } conn->save(); } - connect(conn.data(), &NetworkManager::Connection::unsavedChanged, this, [this] { - Q_EMIT activeConnectionChanged(); - }, Qt::UniqueConnection); + connect(conn.data(), &NetworkManager::Connection::unsavedChanged, this, &WirelessDeviceManagerRealize::activeConnectionChanged, Qt::UniqueConnection); } activeAp->updateStatus(convertStateFromNetworkManager(state)); @@ -1097,7 +1095,17 @@ bool WirelessDeviceManagerRealize::hotspotEnabled() void WirelessDeviceManagerRealize::addNetwork(const NetworkManager::WirelessNetwork::Ptr &network) { // 在当前的网络列表中查找同名SSID的网络,如果查找到了,就更新数据,没有查找到,就新增一条网络 - QList::iterator itApInfo = std::find_if(m_accessPointInfos.begin(), m_accessPointInfos.end(), [ network ](AccessPointInfo *accessPoint) { return accessPoint->accessPoint()->ssid() == network->ssid(); }); + // GBK SSID 下上游 network->ssid() 是 mojibake,与本端显示名(ssidToUtf8)不一致, + // 因此按原始字节匹配:上游 referenceAccessPoint()->rawSsid() vs 本端 AccessPoints::rawSsid() + const QByteArray netRawSsid = network->referenceAccessPoint().isNull() + ? QByteArray() + : network->referenceAccessPoint()->rawSsid(); + QList::iterator itApInfo = std::find_if(m_accessPointInfos.begin(), m_accessPointInfos.end(), [ &netRawSsid, network ](AccessPointInfo *accessPoint) { + const QByteArray apRawSsid = accessPoint->accessPoint()->rawSsid(); + if (!apRawSsid.isEmpty() && !netRawSsid.isEmpty()) + return apRawSsid == netRawSsid; + return accessPoint->accessPoint()->ssid() == network->ssid(); + }); if (itApInfo == m_accessPointInfos.end()) { // 新增的无线网络 AccessPointInfo *apInfo = new AccessPointInfo(m_device, network); @@ -1142,13 +1150,32 @@ void WirelessDeviceManagerRealize::onNetworkAppeared(const QString &ssid) void WirelessDeviceManagerRealize::onNetworkDisappeared(const QString &ssid) { - // 查找移除的网络 + // 不再依赖上游 networkDisappeared 的 ssid 参数做匹配(该参数是上游解码后的显示名, + // 在 GBK SSID 下与 AP 原始字节/本端显示名均不一致,且随上游 KF6 解码实现变化), + // 改为「上游存活 WirelessNetwork 的 rawSsid 集合」与「本端 m_accessPointInfos 的 rawSsid」做差集, + // 不在存活集合中的项即为已消失的网络。 + Q_UNUSED(ssid); + + // 1. 收集上游当前存活的 WirelessNetwork 的 rawSsid 字节集合 + QSet aliveRawSsids; + for (const NetworkManager::WirelessNetwork::Ptr &net : m_device->networks()) { + const NetworkManager::AccessPoint::Ptr refAp = net->referenceAccessPoint(); + if (!refAp.isNull()) + aliveRawSsids.insert(refAp->rawSsid()); + } + + // 2. 本端列表中 rawSsid 不在存活集合里的 → 删除;rawSsid 为空(隐藏网络)时回退显示名比对 QList removeAccessPoints; for (AccessPointInfo *apInfo : m_accessPointInfos) { - if (apInfo->accessPoint()->ssid() != ssid) + const QByteArray raw = apInfo->accessPoint()->rawSsid(); + if (raw.isEmpty()) { + if (apInfo->accessPoint()->ssid() == ssid) + removeAccessPoints << apInfo; continue; + } - removeAccessPoints << apInfo; + if (!aliveRawSsids.contains(raw)) + removeAccessPoints << apInfo; } if (removeAccessPoints.size() == 0) diff --git a/src/impl/serviceinter/accesspointsproxyinter.cpp b/src/impl/serviceinter/accesspointsproxyinter.cpp index cf3055f8d..1cc988e39 100644 --- a/src/impl/serviceinter/accesspointsproxyinter.cpp +++ b/src/impl/serviceinter/accesspointsproxyinter.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -23,6 +23,20 @@ QString AccessPointsProxyInter::ssid() const return m_json.value("Ssid").toString(); } +QByteArray AccessPointsProxyInter::rawSsid() const +{ + // DSS 服务目前仅下发显示用的 Ssid 字符串,未提供原始字节; + // 若服务端未来提供 RawSsid(base64)字段,在此解析返回。 + if (m_json.contains("RawSsid")) { + return QByteArray::fromBase64(m_json.value("RawSsid").toString().toLatin1()); + } + if (m_json.contains("Ssid")) { + return m_json.value("Ssid").toString().toUtf8(); + } + + return QByteArray(); +} + int AccessPointsProxyInter::strength() const { if (m_json.isEmpty()) diff --git a/src/impl/serviceinter/accesspointsproxyinter.h b/src/impl/serviceinter/accesspointsproxyinter.h index 7d18d39ef..6509aa3a6 100644 --- a/src/impl/serviceinter/accesspointsproxyinter.h +++ b/src/impl/serviceinter/accesspointsproxyinter.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -33,6 +33,7 @@ class AccessPointsProxyInter : public AccessPointProxy ConnectionStatus status() const override; bool hidden() const override; bool isWlan6() const override; + QByteArray rawSsid() const override; private: QString m_devicePath; diff --git a/src/impl/serviceinter/deviceinterrealize.cpp b/src/impl/serviceinter/deviceinterrealize.cpp index 140252c7a..7da636af6 100644 --- a/src/impl/serviceinter/deviceinterrealize.cpp +++ b/src/impl/serviceinter/deviceinterrealize.cpp @@ -725,7 +725,7 @@ WirelessConnection *WirelessDeviceInterRealize::findConnectionByAccessPoint(cons if (connection->accessPoints() == accessPoint) return connection; - if (connection->connection()->ssid() == accessPoint->ssid()) + if (connection->connection()->ssid() == accessPoint->rawSsid()) return connection; } diff --git a/src/netutils.cpp b/src/netutils.cpp index 60aa0e5e4..ef8873d3a 100644 --- a/src/netutils.cpp +++ b/src/netutils.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,10 +6,152 @@ #include #include +#include +#include namespace dde { namespace network { +namespace { + +// 语言 → 候选编码(合并 nm_utils.c 的 5 位/2 位语言表,顺序贴近) +QStringList langEncodings(const QLocale &l) +{ + if (l.language() == QLocale::Chinese) { + switch (l.territory()) { + case QLocale::HongKong: + case QLocale::Macau: + case QLocale::Taiwan: + return { QStringLiteral("Big5"), QStringLiteral("EUC-TW") }; + default: + // 简体中文: GB18030 是 GBK/GB2312 超集,一条覆盖 + return { QStringLiteral("GB18030"), QStringLiteral("GB2312") }; + } + } + if (l.language() == QLocale::Japanese) + return { QStringLiteral("EUC-JP"), QStringLiteral("Shift_JIS"), QStringLiteral("ISO-2022-JP") }; + if (l.language() == QLocale::Korean) + return { QStringLiteral("EUC-KR"), QStringLiteral("ISO-2022-KR"), QStringLiteral("Johab") }; + if (l.language() == QLocale::Russian || l.language() == QLocale::Belarusian + || l.language() == QLocale::Bulgarian || l.language() == QLocale::Macedonian) + return { QStringLiteral("KOI8-R"), QStringLiteral("windows-1251"), QStringLiteral("ISO-8859-5") }; + if (l.language() == QLocale::Ukrainian) + return { QStringLiteral("KOI8-U"), QStringLiteral("KOI8-R"), QStringLiteral("windows-1251") }; + + switch (l.language()) { + case QLocale::Arabic: + return { QStringLiteral("ISO-8859-6"), QStringLiteral("windows-1256") }; + case QLocale::Czech: + case QLocale::Croatian: + case QLocale::Hungarian: + case QLocale::Polish: + case QLocale::Romanian: + case QLocale::Serbian: + case QLocale::Slovak: + case QLocale::Slovenian: + return { QStringLiteral("ISO-8859-2"), QStringLiteral("windows-1250") }; + case QLocale::Greek: + return { QStringLiteral("ISO-8859-7"), QStringLiteral("windows-1253") }; + case QLocale::Estonian: + case QLocale::Lithuanian: + case QLocale::Latvian: + return { QStringLiteral("ISO-8859-4"), QStringLiteral("windows-1257") }; + case QLocale::Hebrew: + return { QStringLiteral("ISO-8859-8"), QStringLiteral("windows-1255") }; + case QLocale::Thai: + return { QStringLiteral("ISO-8859-11"), QStringLiteral("windows-874") }; + case QLocale::Turkish: + return { QStringLiteral("ISO-8859-9"), QStringLiteral("windows-1254") }; + default: + break; + } + return {}; +} + +// 候选 = 语言表 + { 系统 charset, iso-8859-1, windows-1251 }(同 _system_encodings_get) +QStringList decodeCandidates(const QLocale &l) +{ + QStringList list = langEncodings(l); + auto sys = QStringDecoder(QStringDecoder::System); + if (sys.isValid()) { + QString n = QString::fromLatin1(sys.name()); + if (!list.contains(n)) + list << n; + } + for (const char *e : { "ISO-8859-1", "windows-1251" }) { + const QString n = QString::fromLatin1(e); + if (!list.contains(n)) + list << n; + } + return list; +} + +} // namespace + +/** + * 将 SSID 原始字节解码为显示用 UTF-8 字符串。 + * + * 实现参考 NetworkManager 上游的 nm_utils_ssid_to_utf8() + * (network-manager/src/libnm-core-impl/nm-utils.c),采用相同的解码策略: + * 1) 输入已是合法 UTF-8 → 原样返回(对应 nm_utils 的 g_utf8_validate 分支) + * 2) 按系统 locale 的语言表尝试候选编码,第一个完整解码成功者生效 + * (对应 nm_utils 的 _system_encodings_for_lang 语言→编码表, + * 如 zh_CN → euc-cn/gb2312/gb18030,GB18030 为 GBK 超集) + * 3) 语言表无命中时回退到默认候选: 系统 charset + iso-8859-1 + windows-1251 + * (对应 nm_utils 的 _system_encodings_get_default) + * 4) 全部失败 → 可打印 ASCII,其余字节替换为 '?' + * (对应 nm_utils 的 g_convert_with_fallback/g_strcanon 兜底) + * + * 与 nm_utils 的区别: 使用 Qt 的 QStringDecoder(内部 ICU)做解码, + * 不依赖 glib/g_convert,亦不引入 libnm 头文件依赖。 + * 注意: 与 nm_utils_ssid_to_utf8 相同,结果仅用于显示,不可用于字节匹配 + * (匹配请使用 AccessPoints::rawSsid() 原始字节)。 + */ +QString ssidToUtf8(const QByteArray &raw) +{ + if (raw.isEmpty()) + return {}; + + // 1) 已是 UTF-8 → 直接返回 + QStringDecoder u8(QStringDecoder::Utf8); + QString out = u8.decode(raw); + if (!u8.hasError()) + return out; + + // 2) 按系统 locale 的候选表逐个试(先验判断编码) + const QLocale sys = QLocale::system(); + for (const QString &enc : decodeCandidates(sys)) { + QStringDecoder d(enc); + if (!d.isValid()) + continue; + d.resetState(); + out = d.decode(raw); + if (!d.hasError()) + return out; + } + + // 3) 兜底: 可打印 ASCII,其余 '?' + QString ascii; + ascii.reserve(raw.size()); + for (char c : raw) + ascii += (c >= 0x20 && c <= 0x7E) ? QChar(c) : QChar('?'); + return ascii; +} + +bool ssidBytesMatch(const QByteArray &connSsid, const QByteArray &rawSsid, const QString &displaySsid) +{ + // 优先按原始字节精确匹配(与 NM 侧字节比较一致),rawSsid 为空(如 DSS 后端) + // 时回退按 UTF-8 显示名匹配历史连接 + return (!rawSsid.isEmpty() && connSsid == rawSsid) || connSsid == displaySsid.toUtf8(); +} + +QByteArray ssidForSave(const QByteArray &rawSsid, const QString &displaySsid) +{ + // 保存连接时优先存 AP 原始字节(保证与 NM 字节匹配一致), + // rawSsid 为空(如隐藏网络)时回退 UTF-8 显示名 + return rawSsid.isEmpty() ? displaySsid.toUtf8() : rawSsid; +} + Connectivity connectivityValue(uint sourceConnectivity) { switch (sourceConnectivity) { diff --git a/src/netutils.h b/src/netutils.h index d44dcff8e..3120f135b 100644 --- a/src/netutils.h +++ b/src/netutils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -33,6 +33,9 @@ namespace network { // using NetworkInter = com::deepin::daemon::Network; Connectivity connectivityValue(uint sourceConnectivity); +QString ssidToUtf8(const QByteArray &raw); // 网络SSID原始字节 → UTF-8,locale 感知解码(类似 nm_utils_ssid_to_utf8) +bool ssidBytesMatch(const QByteArray &connSsid, const QByteArray &rawSsid, const QString &displaySsid); // 连接ssid字节是否匹配某AP:优先原始字节,回退UTF-8显示名 +QByteArray ssidForSave(const QByteArray &rawSsid, const QString &displaySsid); // 保存用ssid字节:优先原始字节,空则回退UTF-8显示名 DeviceStatus convertDeviceStatus(int sourceDeviceStatus); ConnectionStatus convertConnectionStatus(int sourceConnectionStatus); ConnectionStatus convertStateFromNetworkManager(NetworkManager::ActiveConnection::State state); diff --git a/src/wirelessdevice.cpp b/src/wirelessdevice.cpp index 5a60145ec..8a73624e8 100644 --- a/src/wirelessdevice.cpp +++ b/src/wirelessdevice.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -124,6 +124,11 @@ QString AccessPoints::ssid() const return m_proxy->ssid(); } +QByteArray AccessPoints::rawSsid() const +{ + return m_proxy->rawSsid(); +} + int AccessPoints::strength() const { return m_proxy->strength(); diff --git a/src/wirelessdevice.h b/src/wirelessdevice.h index 5c90ab80a..053c6693e 100644 --- a/src/wirelessdevice.h +++ b/src/wirelessdevice.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -90,6 +90,7 @@ class AccessPoints : public QObject bool connected() const; // 网络是否连接成功 ConnectionStatus status() const; // 当前网络的连接状态 bool hidden() const; // 是否为隐藏网络 + QByteArray rawSsid() const; // 网络SSID原始字节,用于与NM连接字节精确匹配/保存 WlanType type() const; Q_SIGNALS: