File indexing completed on 2023-09-24 09:38:43
0001 /* 0002 SPDX-FileCopyrightText: 2013-2014 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 "handler.h" 0008 #include "configuration.h" 0009 #include "connectioneditordialog.h" 0010 #include "plasma_nm_libs.h" 0011 #include "uiutils.h" 0012 0013 #include <NetworkManagerQt/AccessPoint> 0014 #include <NetworkManagerQt/ActiveConnection> 0015 #include <NetworkManagerQt/GsmSetting> 0016 #include <NetworkManagerQt/Ipv4Setting> 0017 #include <NetworkManagerQt/Manager> 0018 #include <NetworkManagerQt/Setting> 0019 #include <NetworkManagerQt/WiredDevice> 0020 #include <NetworkManagerQt/WiredSetting> 0021 #include <NetworkManagerQt/WirelessDevice> 0022 #include <NetworkManagerQt/WirelessSetting> 0023 0024 #include <libnm/nm-vpn-plugin-info.h> 0025 0026 #include <ModemManagerQt/Manager> 0027 #include <ModemManagerQt/ModemDevice> 0028 0029 #include <QDBusError> 0030 #include <QDBusMetaType> 0031 #include <QDBusPendingReply> 0032 #include <QFile> 0033 #include <QIcon> 0034 0035 #include <KIO/OpenUrlJob> 0036 #include <KLocalizedString> 0037 #include <KNotification> 0038 #include <KOSRelease> 0039 #include <KPluginMetaData> 0040 #include <KProcess> 0041 #include <KUser> 0042 #include <KWallet> 0043 #include <KWindowSystem> 0044 0045 #include <nm-client.h> 0046 0047 #define AGENT_SERVICE "org.kde.kded5" 0048 #define AGENT_PATH "/modules/networkmanagement" 0049 #define AGENT_IFACE "org.kde.plasmanetworkmanagement" 0050 0051 // 10 seconds 0052 #define NM_REQUESTSCAN_LIMIT_RATE 10000 0053 0054 Handler::Handler(QObject *parent) 0055 : QObject(parent) 0056 , m_tmpWirelessEnabled(NetworkManager::isWirelessEnabled()) 0057 , m_tmpWwanEnabled(NetworkManager::isWwanEnabled()) 0058 { 0059 QDBusConnection::sessionBus().connect(QStringLiteral(AGENT_SERVICE), 0060 QStringLiteral(AGENT_PATH), 0061 QStringLiteral(AGENT_IFACE), 0062 QStringLiteral("secretsError"), 0063 this, 0064 SLOT(secretAgentError(QString, QString))); 0065 0066 if (!Configuration::self().hotspotConnectionPath().isEmpty()) { 0067 NetworkManager::ActiveConnection::Ptr hotspot = NetworkManager::findActiveConnection(Configuration::self().hotspotConnectionPath()); 0068 if (!hotspot) { 0069 Configuration::self().setHotspotConnectionPath(QString()); 0070 } 0071 } 0072 0073 m_hotspotSupported = checkHotspotSupported(); 0074 0075 if (NetworkManager::checkVersion(1, 16, 0)) { 0076 connect(NetworkManager::notifier(), &NetworkManager::Notifier::primaryConnectionTypeChanged, this, &Handler::primaryConnectionTypeChanged); 0077 } 0078 } 0079 0080 Handler::~Handler() = default; 0081 0082 void Handler::activateConnection(const QString &connection, const QString &device, const QString &specificObject) 0083 { 0084 NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); 0085 0086 if (!con) { 0087 qCWarning(PLASMA_NM_LIBS_LOG) << "Not possible to activate this connection"; 0088 return; 0089 } 0090 0091 if (con->settings()->connectionType() == NetworkManager::ConnectionSettings::Vpn) { 0092 NetworkManager::VpnSetting::Ptr vpnSetting = con->settings()->setting(NetworkManager::Setting::Vpn).staticCast<NetworkManager::VpnSetting>(); 0093 if (vpnSetting) { 0094 qCDebug(PLASMA_NM_LIBS_LOG) << "Checking VPN" << con->name() << "type:" << vpnSetting->serviceType(); 0095 0096 // Check missing plasma-nm VPN plugin 0097 0098 const auto filter = [vpnSetting](const KPluginMetaData &md) -> bool { 0099 return md.value(QStringLiteral("X-NetworkManager-Services")) == vpnSetting->serviceType(); 0100 }; 0101 0102 const QVector<KPluginMetaData> plasmaNmPlugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/network/vpn"), filter); 0103 0104 const QString pluginBaseName = vpnSetting->serviceType().remove(QLatin1String("org.freedesktop.NetworkManager.")); 0105 0106 if (plasmaNmPlugins.empty()) { 0107 qCWarning(PLASMA_NM_LIBS_LOG) << "VPN" << vpnSetting->serviceType() << "not found, skipping"; 0108 auto notification = new KNotification(QStringLiteral("MissingVpnPlugin"), KNotification::Persistent, this); 0109 notification->setComponentName(QStringLiteral("networkmanagement")); 0110 notification->setTitle(con->name()); 0111 notification->setText(i18n("Plasma is missing support for '%1' VPN connections.", pluginBaseName)); 0112 notification->setIconName(QStringLiteral("dialog-error")); 0113 notification->setActions({i18n("Report Bug")}); 0114 connect(notification, &KNotification::action1Activated, this, [notification] { 0115 auto *job = new KIO::OpenUrlJob(QUrl(KOSRelease().bugReportUrl())); 0116 job->setStartupId(notification->xdgActivationToken().toUtf8()); 0117 job->start(); 0118 }); 0119 0120 notification->sendEvent(); 0121 0122 return; 0123 } 0124 0125 // Check missing NetworkManager VPN plugin 0126 GSList *networkManagerPlugins = nullptr; 0127 networkManagerPlugins = nm_vpn_plugin_info_list_load(); 0128 0129 NMVpnPluginInfo *plugin_info = nm_vpn_plugin_info_list_find_by_service(networkManagerPlugins, vpnSetting->serviceType().toStdString().c_str()); 0130 0131 if (!plugin_info) { 0132 qCWarning(PLASMA_NM_LIBS_LOG) << "VPN" << vpnSetting->serviceType() << "not found, skipping"; 0133 auto notification = new KNotification(QStringLiteral("MissingVpnPlugin"), KNotification::Persistent, this); 0134 notification->setComponentName(QStringLiteral("networkmanagement")); 0135 notification->setTitle(con->name()); 0136 notification->setText(i18n("NetworkManager is missing support for '%1' VPN connections.", pluginBaseName)); 0137 notification->setIconName(QStringLiteral("dialog-error")); 0138 notification->setActions({i18n("Install")}); 0139 0140 connect(notification, &KNotification::action1Activated, this, [notification, pluginBaseName] { 0141 auto *job = new KIO::OpenUrlJob(QUrl(QStringLiteral("appstream:network-manager-") + pluginBaseName)); 0142 job->setStartupId(notification->xdgActivationToken().toUtf8()); 0143 job->start(); 0144 }); 0145 0146 notification->sendEvent(); 0147 return; 0148 } 0149 } 0150 } 0151 0152 if (con->settings()->connectionType() == NetworkManager::ConnectionSettings::Gsm) { 0153 NetworkManager::ModemDevice::Ptr nmModemDevice = NetworkManager::findNetworkInterface(device).objectCast<NetworkManager::ModemDevice>(); 0154 if (nmModemDevice) { 0155 ModemManager::ModemDevice::Ptr mmModemDevice = ModemManager::findModemDevice(nmModemDevice->udi()); 0156 if (mmModemDevice) { 0157 ModemManager::Modem::Ptr modem = mmModemDevice->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>(); 0158 NetworkManager::GsmSetting::Ptr gsmSetting = con->settings()->setting(NetworkManager::Setting::Gsm).staticCast<NetworkManager::GsmSetting>(); 0159 if (gsmSetting && gsmSetting->pinFlags() == NetworkManager::Setting::NotSaved && modem && modem->unlockRequired() > MM_MODEM_LOCK_NONE) { 0160 QDBusInterface managerIface(QStringLiteral("org.kde.plasmanetworkmanagement"), 0161 QStringLiteral("/org/kde/plasmanetworkmanagement"), 0162 QStringLiteral("org.kde.plasmanetworkmanagement"), 0163 QDBusConnection::sessionBus(), 0164 this); 0165 managerIface.call(QStringLiteral("unlockModem"), mmModemDevice->uni()); 0166 connect(modem.data(), &ModemManager::Modem::unlockRequiredChanged, this, &Handler::unlockRequiredChanged); 0167 m_tmpConnectionPath = connection; 0168 m_tmpDevicePath = device; 0169 m_tmpSpecificPath = specificObject; 0170 return; 0171 } 0172 } 0173 } 0174 } 0175 0176 QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::activateConnection(connection, device, specificObject); 0177 auto watcher = new QDBusPendingCallWatcher(reply, this); 0178 watcher->setProperty("action", Handler::ActivateConnection); 0179 watcher->setProperty("connection", con->name()); 0180 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0181 } 0182 0183 void Handler::requestWifiCode(const QString &connectionPath, const QString &ssid, int _securityType, const QString &connectionName) 0184 { 0185 if (!m_requestWifiCodeWatcher.isNull()) { 0186 delete m_requestWifiCodeWatcher; 0187 } 0188 0189 auto securityType = static_cast<NetworkManager::WirelessSecurityType>(_securityType); 0190 0191 QString ret = QStringLiteral("WIFI:S:") + ssid + QLatin1Char(';'); 0192 if (securityType != NetworkManager::NoneSecurity) { 0193 switch (securityType) { 0194 case NetworkManager::NoneSecurity: 0195 break; 0196 case NetworkManager::StaticWep: 0197 ret += QStringLiteral("T:WEP;"); 0198 break; 0199 case NetworkManager::WpaPsk: 0200 case NetworkManager::Wpa2Psk: 0201 ret += QStringLiteral("T:WPA;"); 0202 break; 0203 case NetworkManager::SAE: 0204 ret += QStringLiteral("T:SAE;"); 0205 break; 0206 default: 0207 case NetworkManager::DynamicWep: 0208 case NetworkManager::WpaEap: 0209 case NetworkManager::Wpa2Eap: 0210 case NetworkManager::Wpa3SuiteB192: 0211 case NetworkManager::Leap: 0212 Q_EMIT wifiCodeReceived(QString(), connectionName); 0213 return; 0214 } 0215 } 0216 0217 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionPath); 0218 if (!connection) { 0219 Q_EMIT wifiCodeReceived(QString(), connectionName); 0220 return; 0221 } 0222 0223 const auto key = QStringLiteral("802-11-wireless-security"); 0224 auto reply = connection->secrets(key); 0225 m_requestWifiCodeWatcher = new QDBusPendingCallWatcher(reply, this); 0226 m_requestWifiCodeWatcher->setProperty("key", key); 0227 m_requestWifiCodeWatcher->setProperty("ret", ret); 0228 m_requestWifiCodeWatcher->setProperty("securityType", static_cast<int>(securityType)); 0229 m_requestWifiCodeWatcher->setProperty("connectionName", connectionName); 0230 connect(m_requestWifiCodeWatcher, &QDBusPendingCallWatcher::finished, this, &Handler::slotRequestWifiCode); 0231 } 0232 0233 void Handler::addAndActivateConnection(const QString &device, const QString &specificObject, const QString &password) 0234 { 0235 NetworkManager::AccessPoint::Ptr ap; 0236 NetworkManager::WirelessDevice::Ptr wifiDev; 0237 for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) { 0238 if (dev->type() == NetworkManager::Device::Wifi) { 0239 wifiDev = dev.objectCast<NetworkManager::WirelessDevice>(); 0240 ap = wifiDev->findAccessPoint(specificObject); 0241 if (ap) { 0242 break; 0243 } 0244 } 0245 } 0246 0247 if (!ap) { 0248 return; 0249 } 0250 0251 NetworkManager::ConnectionSettings::Ptr settings = 0252 NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); 0253 settings->setId(ap->ssid()); 0254 settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); 0255 settings->setAutoconnect(true); 0256 0257 UiUtils::setConnectionDefaultPermissions(settings); 0258 0259 NetworkManager::WirelessSetting::Ptr wifiSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>(); 0260 wifiSetting->setInitialized(true); 0261 wifiSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>(); 0262 wifiSetting->setSsid(ap->ssid().toUtf8()); 0263 if (ap->mode() == NetworkManager::AccessPoint::Adhoc) { 0264 wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); 0265 } 0266 NetworkManager::WirelessSecuritySetting::Ptr wifiSecurity = 0267 settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast<NetworkManager::WirelessSecuritySetting>(); 0268 0269 NetworkManager::WirelessSecurityType securityType = NetworkManager::findBestWirelessSecurity(wifiDev->wirelessCapabilities(), 0270 true, 0271 (ap->mode() == NetworkManager::AccessPoint::Adhoc), 0272 ap->capabilities(), 0273 ap->wpaFlags(), 0274 ap->rsnFlags()); 0275 0276 if (securityType != NetworkManager::NoneSecurity) { 0277 wifiSecurity->setInitialized(true); 0278 wifiSetting->setSecurity(QStringLiteral("802-11-wireless-security")); 0279 } 0280 0281 if (securityType == NetworkManager::Leap // 0282 || securityType == NetworkManager::DynamicWep // 0283 || securityType == NetworkManager::Wpa3SuiteB192 // 0284 || securityType == NetworkManager::Wpa2Eap // 0285 || securityType == NetworkManager::WpaEap) { 0286 if (securityType == NetworkManager::DynamicWep || securityType == NetworkManager::Leap) { 0287 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Ieee8021x); 0288 if (securityType == NetworkManager::Leap) { 0289 wifiSecurity->setAuthAlg(NetworkManager::WirelessSecuritySetting::Leap); 0290 } 0291 } else if (securityType == NetworkManager::Wpa3SuiteB192) { 0292 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEapSuiteB192); 0293 } else { 0294 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); 0295 } 0296 m_tmpConnectionUuid = settings->uuid(); 0297 m_tmpDevicePath = device; 0298 m_tmpSpecificPath = specificObject; 0299 0300 QPointer<ConnectionEditorDialog> editor = new ConnectionEditorDialog(settings); 0301 editor->setAttribute(Qt::WA_DeleteOnClose); 0302 editor->show(); 0303 KWindowSystem::setState(editor->winId(), NET::KeepAbove); 0304 connect(editor.data(), &ConnectionEditorDialog::accepted, [editor, device, specificObject, this]() { // 0305 addAndActivateConnectionDBus(editor->setting(), device, specificObject); 0306 }); 0307 editor->setModal(true); 0308 editor->show(); 0309 } else { 0310 if (securityType == NetworkManager::StaticWep) { 0311 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep); 0312 wifiSecurity->setWepKey0(password); 0313 } else { 0314 if (ap->mode() == NetworkManager::AccessPoint::Adhoc) { 0315 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone); 0316 } else if (securityType == NetworkManager::SAE) { 0317 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::SAE); 0318 } else { 0319 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); 0320 } 0321 wifiSecurity->setPsk(password); 0322 } 0323 addAndActivateConnectionDBus(settings->toMap(), device, specificObject); 0324 } 0325 0326 settings.clear(); 0327 } 0328 0329 void Handler::addConnection(const NMVariantMapMap &map) 0330 { 0331 QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addConnection(map); 0332 auto watcher = new QDBusPendingCallWatcher(reply, this); 0333 watcher->setProperty("action", AddConnection); 0334 watcher->setProperty("connection", map.value(QStringLiteral("connection")).value(QStringLiteral("id"))); 0335 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0336 } 0337 0338 struct AddConnectionData { 0339 QString id; 0340 Handler *handler; 0341 }; 0342 0343 void add_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data) 0344 { 0345 AddConnectionData *data = static_cast<AddConnectionData *>(user_data); 0346 0347 GError *error = nullptr; 0348 NMRemoteConnection *connection = nm_client_add_connection2_finish(NM_CLIENT(client), result, NULL, &error); 0349 0350 if (error) { 0351 KNotification *notification = new KNotification(QStringLiteral("FailedToAddConnection"), KNotification::CloseOnTimeout, data->handler); 0352 notification->setTitle(i18n("Failed to add connection %1", data->id)); 0353 notification->setComponentName(QStringLiteral("networkmanagement")); 0354 notification->setText(QString::fromUtf8(error->message)); 0355 notification->setIconName(QStringLiteral("dialog-warning")); 0356 notification->sendEvent(); 0357 0358 g_error_free(error); 0359 } else { 0360 KNotification *notification = new KNotification(QStringLiteral("ConnectionAdded"), KNotification::CloseOnTimeout, data->handler); 0361 notification->setText(i18n("Connection %1 has been added", data->id)); 0362 notification->setComponentName(QStringLiteral("networkmanagement")); 0363 notification->setTitle(data->id); 0364 notification->setIconName(QStringLiteral("dialog-information")); 0365 notification->sendEvent(); 0366 0367 g_object_unref(connection); 0368 } 0369 0370 delete data; 0371 } 0372 0373 void Handler::addConnection(NMConnection *connection) 0374 { 0375 NMClient *client = nm_client_new(nullptr, nullptr); 0376 0377 AddConnectionData *userData = new AddConnectionData{QString::fromUtf8(nm_connection_get_id(connection)), this}; 0378 0379 nm_client_add_connection2(client, 0380 nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL), 0381 NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK, 0382 nullptr, 0383 true, 0384 nullptr, 0385 add_connection_cb, 0386 userData); 0387 } 0388 0389 void Handler::addAndActivateConnectionDBus(const NMVariantMapMap &map, const QString &device, const QString &specificObject) 0390 { 0391 QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addAndActivateConnection(map, device, specificObject); 0392 auto watcher = new QDBusPendingCallWatcher(reply, this); 0393 watcher->setProperty("action", AddAndActivateConnection); 0394 watcher->setProperty("connection", map.value(QStringLiteral("connection")).value(QStringLiteral("id"))); 0395 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0396 } 0397 0398 void Handler::deactivateConnection(const QString &connection, const QString &device) 0399 { 0400 NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); 0401 0402 if (!con) { 0403 qCWarning(PLASMA_NM_LIBS_LOG) << "Not possible to deactivate this connection"; 0404 return; 0405 } 0406 0407 QDBusPendingReply<> reply; 0408 for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) { 0409 if (active->uuid() == con->uuid() && ((!active->devices().isEmpty() && active->devices().first() == device) || active->vpn())) { 0410 if (active->vpn()) { 0411 reply = NetworkManager::deactivateConnection(active->path()); 0412 } else { 0413 NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first()); 0414 if (device) { 0415 reply = device->disconnectInterface(); 0416 } 0417 } 0418 } 0419 } 0420 0421 auto watcher = new QDBusPendingCallWatcher(reply, this); 0422 watcher->setProperty("action", Handler::DeactivateConnection); 0423 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0424 } 0425 0426 void Handler::disconnectAll() 0427 { 0428 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0429 device->disconnectInterface(); 0430 } 0431 } 0432 0433 void Handler::enableAirplaneMode(bool enable) 0434 { 0435 if (enable) { 0436 m_tmpWirelessEnabled = NetworkManager::isWirelessEnabled(); 0437 m_tmpWwanEnabled = NetworkManager::isWwanEnabled(); 0438 enableBluetooth(false); 0439 enableWireless(false); 0440 enableWwan(false); 0441 } else { 0442 enableBluetooth(true); 0443 if (m_tmpWirelessEnabled) { 0444 enableWireless(true); 0445 } 0446 if (m_tmpWwanEnabled) { 0447 enableWwan(true); 0448 } 0449 } 0450 } 0451 0452 template<typename T> 0453 void makeDBusCall(const QDBusMessage &message, QObject *context, std::function<void(QDBusPendingReply<T>)> func) 0454 { 0455 QDBusPendingReply<T> reply = QDBusConnection::systemBus().asyncCall(message); 0456 auto watcher = new QDBusPendingCallWatcher(reply, context); 0457 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, context, [func](QDBusPendingCallWatcher *watcher) { 0458 const QDBusPendingReply<T> reply = *watcher; 0459 if (!reply.isValid()) { 0460 qCWarning(PLASMA_NM_LIBS_LOG) << reply.error().message(); 0461 return; 0462 } 0463 func(reply); 0464 watcher->deleteLater(); 0465 }); 0466 } 0467 0468 void setBluetoothEnabled(const QString &path, bool enabled) 0469 { 0470 QDBusMessage message = 0471 QDBusMessage::createMethodCall(QStringLiteral("org.bluez"), path, QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("Set")); 0472 QList<QVariant> arguments; 0473 arguments << QLatin1String("org.bluez.Adapter1"); 0474 arguments << QLatin1String("Powered"); 0475 arguments << QVariant::fromValue(QDBusVariant(QVariant(enabled))); 0476 message.setArguments(arguments); 0477 QDBusConnection::systemBus().asyncCall(message); 0478 } 0479 0480 void Handler::enableBluetooth(bool enable) 0481 { 0482 qDBusRegisterMetaType<QMap<QDBusObjectPath, NMVariantMapMap>>(); 0483 0484 const QDBusMessage getObjects = QDBusMessage::createMethodCall("org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 0485 0486 makeDBusCall<QMap<QDBusObjectPath, NMVariantMapMap>>(getObjects, this, [enable, this](const auto reply) { 0487 for (const QDBusObjectPath &path : reply.value().keys()) { 0488 const QString objPath = path.path(); 0489 qCDebug(PLASMA_NM_LIBS_LOG) << "inspecting path" << objPath; 0490 const QStringList interfaces = reply.value().value(path).keys(); 0491 qCDebug(PLASMA_NM_LIBS_LOG) << "interfaces:" << interfaces; 0492 0493 if (!interfaces.contains(QStringLiteral("org.bluez.Adapter1"))) { 0494 continue; 0495 } 0496 0497 // We need to check previous state first 0498 if (!enable) { 0499 QDBusMessage getPowered = QDBusMessage::createMethodCall("org.bluez", objPath, "org.freedesktop.DBus.Properties", "Get"); 0500 const QList<QVariant> arguments{QLatin1String("org.bluez.Adapter1"), QLatin1String("Powered")}; 0501 getPowered.setArguments(arguments); 0502 0503 makeDBusCall<QVariant>(getPowered, this, [objPath, this](const auto reply) { 0504 m_bluetoothAdapters.insert(objPath, reply.value().toBool()); 0505 setBluetoothEnabled(objPath, false); 0506 }); 0507 } else if (m_bluetoothAdapters.value(objPath)) { 0508 setBluetoothEnabled(objPath, true); 0509 } 0510 } 0511 }); 0512 } 0513 0514 void Handler::enableNetworking(bool enable) 0515 { 0516 NetworkManager::setNetworkingEnabled(enable); 0517 } 0518 0519 void Handler::enableWireless(bool enable) 0520 { 0521 NetworkManager::setWirelessEnabled(enable); 0522 } 0523 0524 void Handler::enableWwan(bool enable) 0525 { 0526 NetworkManager::setWwanEnabled(enable); 0527 } 0528 0529 void Handler::removeConnection(const QString &connection) 0530 { 0531 NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); 0532 0533 if (!con || con->uuid().isEmpty()) { 0534 qCWarning(PLASMA_NM_LIBS_LOG) << "Not possible to remove connection " << connection; 0535 return; 0536 } 0537 0538 // Remove slave connections 0539 for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) { 0540 NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); 0541 if (settings->master() == con->uuid()) { 0542 connection->remove(); 0543 } 0544 } 0545 0546 QDBusPendingReply<> reply = con->remove(); 0547 auto watcher = new QDBusPendingCallWatcher(reply, this); 0548 watcher->setProperty("action", Handler::RemoveConnection); 0549 watcher->setProperty("connection", con->name()); 0550 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0551 } 0552 0553 void Handler::updateConnection(const NetworkManager::Connection::Ptr &connection, const NMVariantMapMap &map) 0554 { 0555 QDBusPendingReply<> reply = connection->update(map); 0556 auto watcher = new QDBusPendingCallWatcher(reply, this); 0557 watcher->setProperty("action", UpdateConnection); 0558 watcher->setProperty("connection", connection->name()); 0559 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0560 } 0561 0562 void Handler::requestScan(const QString &interface) 0563 { 0564 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0565 if (device->type() == NetworkManager::Device::Wifi) { 0566 NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>(); 0567 0568 if (wifiDevice && wifiDevice->state() != NetworkManager::WirelessDevice::Unavailable) { 0569 if (!interface.isEmpty() && interface != wifiDevice->interfaceName()) { 0570 continue; 0571 } 0572 0573 if (!checkRequestScanRateLimit(wifiDevice)) { 0574 QDateTime now = QDateTime::currentDateTime(); 0575 // for NM < 1.12, lastScan is not available 0576 QDateTime lastScan = wifiDevice->lastScan(); 0577 QDateTime lastRequestScan = wifiDevice->lastRequestScan(); 0578 // Compute the next time we can run a scan 0579 int timeout = NM_REQUESTSCAN_LIMIT_RATE; 0580 if (lastScan.isValid() && lastScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE) { 0581 timeout = NM_REQUESTSCAN_LIMIT_RATE - lastScan.msecsTo(now); 0582 } else if (lastRequestScan.isValid() && lastRequestScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE) { 0583 timeout = NM_REQUESTSCAN_LIMIT_RATE - lastRequestScan.msecsTo(now); 0584 } 0585 qCDebug(PLASMA_NM_LIBS_LOG) << "Rescheduling a request scan for" << wifiDevice->interfaceName() << "in" << timeout; 0586 scheduleRequestScan(wifiDevice->interfaceName(), timeout); 0587 0588 if (!interface.isEmpty()) { 0589 return; 0590 } 0591 continue; 0592 } else if (m_wirelessScanRetryTimer.contains(interface)) { 0593 m_wirelessScanRetryTimer.value(interface)->stop(); 0594 delete m_wirelessScanRetryTimer.take(interface); 0595 } 0596 0597 qCDebug(PLASMA_NM_LIBS_LOG) << "Requesting wifi scan on device" << wifiDevice->interfaceName(); 0598 incrementScansCount(); 0599 QDBusPendingReply<> reply = wifiDevice->requestScan(); 0600 auto watcher = new QDBusPendingCallWatcher(reply, this); 0601 watcher->setProperty("action", Handler::RequestScan); 0602 watcher->setProperty("interface", wifiDevice->interfaceName()); 0603 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0604 } 0605 } 0606 } 0607 } 0608 0609 void Handler::incrementScansCount() 0610 { 0611 m_ongoingScansCount += 1; 0612 if (m_ongoingScansCount == 1) { 0613 Q_EMIT scanningChanged(); 0614 } 0615 } 0616 0617 void Handler::decrementScansCount() 0618 { 0619 if (m_ongoingScansCount == 0) { 0620 qCDebug(PLASMA_NM_LIBS_LOG) << "Extra decrementScansCount() called"; 0621 return; 0622 } 0623 m_ongoingScansCount -= 1; 0624 if (m_ongoingScansCount == 0) { 0625 Q_EMIT scanningChanged(); 0626 } 0627 } 0628 0629 void Handler::createHotspot() 0630 { 0631 bool foundInactive = false; 0632 bool useApMode = false; 0633 NetworkManager::WirelessDevice::Ptr wifiDev; 0634 0635 NetworkManager::ConnectionSettings::Ptr connectionSettings; 0636 connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); 0637 0638 NetworkManager::WirelessSetting::Ptr wifiSetting = 0639 connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>(); 0640 wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); 0641 wifiSetting->setSsid(Configuration::self().hotspotName().toUtf8()); 0642 0643 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0644 if (device->type() == NetworkManager::Device::Wifi) { 0645 wifiDev = device.objectCast<NetworkManager::WirelessDevice>(); 0646 if (wifiDev) { 0647 if (!wifiDev->isActive()) { 0648 foundInactive = true; 0649 } else { 0650 // Prefer previous device if it was inactive 0651 if (foundInactive) { 0652 break; 0653 } 0654 } 0655 0656 if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { 0657 useApMode = true; 0658 } 0659 0660 // We prefer inactive wireless card with AP capabilities 0661 if (foundInactive && useApMode) { 0662 break; 0663 } 0664 } 0665 } 0666 } 0667 0668 if (!wifiDev) { 0669 qCWarning(PLASMA_NM_LIBS_LOG) << "Failed to create hotspot: missing wireless device"; 0670 return; 0671 } 0672 0673 wifiSetting->setInitialized(true); 0674 wifiSetting->setMode(useApMode ? NetworkManager::WirelessSetting::Ap : NetworkManager::WirelessSetting::Adhoc); 0675 0676 if (!Configuration::self().hotspotPassword().isEmpty()) { 0677 NetworkManager::WirelessSecuritySetting::Ptr wifiSecurity = 0678 connectionSettings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast<NetworkManager::WirelessSecuritySetting>(); 0679 wifiSecurity->setInitialized(true); 0680 0681 if (useApMode) { 0682 // Use WPA2 0683 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); 0684 wifiSecurity->setPsk(Configuration::self().hotspotPassword()); 0685 wifiSecurity->setPskFlags(NetworkManager::Setting::AgentOwned); 0686 } else { 0687 // Use WEP 0688 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep); 0689 wifiSecurity->setWepKeyType(NetworkManager::WirelessSecuritySetting::Passphrase); 0690 wifiSecurity->setWepTxKeyindex(0); 0691 wifiSecurity->setWepKey0(Configuration::self().hotspotPassword()); 0692 wifiSecurity->setWepKeyFlags(NetworkManager::Setting::AgentOwned); 0693 wifiSecurity->setAuthAlg(NetworkManager::WirelessSecuritySetting::Open); 0694 } 0695 } 0696 0697 NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast<NetworkManager::Ipv4Setting>(); 0698 ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Shared); 0699 ipv4Setting->setInitialized(true); 0700 0701 connectionSettings->setId(Configuration::self().hotspotName()); 0702 connectionSettings->setAutoconnect(false); 0703 connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); 0704 0705 const QVariantMap options = {{QLatin1String("persist"), QLatin1String("volatile")}}; 0706 0707 QDBusPendingReply<QDBusObjectPath, QDBusObjectPath, QVariantMap> reply = 0708 NetworkManager::addAndActivateConnection2(connectionSettings->toMap(), wifiDev->uni(), QString(), options); 0709 auto watcher = new QDBusPendingCallWatcher(reply, this); 0710 watcher->setProperty("action", Handler::CreateHotspot); 0711 watcher->setProperty("connection", Configuration::self().hotspotName()); 0712 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0713 connect(watcher, &QDBusPendingCallWatcher::finished, this, QOverload<QDBusPendingCallWatcher *>::of(&Handler::hotspotCreated)); 0714 } 0715 0716 void Handler::stopHotspot() 0717 { 0718 const QString activeConnectionPath = Configuration::self().hotspotConnectionPath(); 0719 0720 if (activeConnectionPath.isEmpty()) { 0721 return; 0722 } 0723 0724 NetworkManager::ActiveConnection::Ptr hotspot = NetworkManager::findActiveConnection(activeConnectionPath); 0725 0726 if (!hotspot) { 0727 return; 0728 } 0729 0730 NetworkManager::deactivateConnection(activeConnectionPath); 0731 Configuration::self().setHotspotConnectionPath(QString()); 0732 0733 Q_EMIT hotspotDisabled(); 0734 } 0735 0736 bool Handler::checkRequestScanRateLimit(const NetworkManager::WirelessDevice::Ptr &wifiDevice) 0737 { 0738 QDateTime now = QDateTime::currentDateTime(); 0739 QDateTime lastScan = wifiDevice->lastScan(); 0740 QDateTime lastRequestScan = wifiDevice->lastRequestScan(); 0741 0742 // if the last scan finished within the last 10 seconds 0743 bool ret = lastScan.isValid() && lastScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE; 0744 // or if the last Request was sent within the last 10 seconds 0745 ret |= lastRequestScan.isValid() && lastRequestScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE; 0746 // skip the request scan 0747 if (ret) { 0748 qCDebug(PLASMA_NM_LIBS_LOG) << "Last scan finished" << lastScan.msecsTo(now) << "ms ago and last request scan was sent" // 0749 << lastRequestScan.msecsTo(now) << "ms ago, Skipping scanning interface:" << wifiDevice->interfaceName(); 0750 return false; 0751 } 0752 return true; 0753 } 0754 0755 bool Handler::checkHotspotSupported() 0756 { 0757 if (NetworkManager::checkVersion(1, 16, 0)) { 0758 bool unusedWifiFound = false; 0759 bool wifiFound = false; 0760 0761 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0762 if (device->type() == NetworkManager::Device::Wifi) { 0763 wifiFound = true; 0764 0765 NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast<NetworkManager::WirelessDevice>(); 0766 if (wifiDev && !wifiDev->isActive()) { 0767 unusedWifiFound = true; 0768 } 0769 } 0770 } 0771 0772 if (!wifiFound) { 0773 return false; 0774 } 0775 0776 if (unusedWifiFound) { 0777 return true; 0778 } 0779 0780 // Check if the primary connection which is used for internet connectivity is not using WiFi 0781 if (NetworkManager::primaryConnectionType() != NetworkManager::ConnectionSettings::Wireless) { 0782 return true; 0783 } 0784 } 0785 0786 return false; 0787 } 0788 0789 void Handler::scheduleRequestScan(const QString &interface, int timeout) 0790 { 0791 QTimer *timer; 0792 if (!m_wirelessScanRetryTimer.contains(interface)) { 0793 // create a timer for the interface 0794 timer = new QTimer(); 0795 timer->setSingleShot(true); 0796 m_wirelessScanRetryTimer.insert(interface, timer); 0797 auto retryAction = [this, interface]() { 0798 requestScan(interface); 0799 }; 0800 connect(timer, &QTimer::timeout, this, retryAction); 0801 } else { 0802 // set the new value for an existing timer 0803 timer = m_wirelessScanRetryTimer.value(interface); 0804 if (timer->isActive()) { 0805 timer->stop(); 0806 } 0807 } 0808 0809 // +1 ms is added to avoid having the scan being rejetted by nm 0810 // because it is run at the exact last millisecond of the requestScan threshold 0811 timer->setInterval(timeout + 1); 0812 timer->start(); 0813 } 0814 0815 void Handler::scanRequestFailed(const QString &interface) 0816 { 0817 scheduleRequestScan(interface, 2000); 0818 } 0819 0820 void Handler::secretAgentError(const QString &connectionPath, const QString &message) 0821 { 0822 // If the password was wrong, forget it 0823 removeConnection(connectionPath); 0824 Q_EMIT connectionActivationFailed(connectionPath, message); 0825 } 0826 0827 void Handler::replyFinished(QDBusPendingCallWatcher *watcher) 0828 { 0829 QDBusPendingReply<> reply = *watcher; 0830 if (reply.isError() || !reply.isValid()) { 0831 KNotification *notification = nullptr; 0832 QString error = reply.error().message(); 0833 Handler::HandlerAction action = (Handler::HandlerAction)watcher->property("action").toUInt(); 0834 switch (action) { 0835 case Handler::ActivateConnection: 0836 notification = new KNotification(QStringLiteral("FailedToActivateConnection"), KNotification::CloseOnTimeout, this); 0837 notification->setTitle(i18n("Failed to activate %1", watcher->property("connection").toString())); 0838 break; 0839 case Handler::AddAndActivateConnection: 0840 notification = new KNotification(QStringLiteral("FailedToAddConnection"), KNotification::CloseOnTimeout, this); 0841 notification->setTitle(i18n("Failed to add %1", watcher->property("connection").toString())); 0842 break; 0843 case Handler::AddConnection: 0844 notification = new KNotification(QStringLiteral("FailedToAddConnection"), KNotification::CloseOnTimeout, this); 0845 notification->setTitle(i18n("Failed to add connection %1", watcher->property("connection").toString())); 0846 break; 0847 case Handler::DeactivateConnection: 0848 notification = new KNotification(QStringLiteral("FailedToDeactivateConnection"), KNotification::CloseOnTimeout, this); 0849 notification->setTitle(i18n("Failed to deactivate %1", watcher->property("connection").toString())); 0850 break; 0851 case Handler::RemoveConnection: 0852 notification = new KNotification(QStringLiteral("FailedToRemoveConnection"), KNotification::CloseOnTimeout, this); 0853 notification->setTitle(i18n("Failed to remove %1", watcher->property("connection").toString())); 0854 break; 0855 case Handler::UpdateConnection: 0856 notification = new KNotification(QStringLiteral("FailedToUpdateConnection"), KNotification::CloseOnTimeout, this); 0857 notification->setTitle(i18n("Failed to update connection %1", watcher->property("connection").toString())); 0858 break; 0859 case Handler::RequestScan: { 0860 const QString interface = watcher->property("interface").toString(); 0861 qCWarning(PLASMA_NM_LIBS_LOG) << "Wireless scan on" << interface << "failed:" << error; 0862 scanRequestFailed(interface); 0863 decrementScansCount(); 0864 break; 0865 } 0866 case Handler::CreateHotspot: 0867 notification = new KNotification(QStringLiteral("FailedToCreateHotspot"), KNotification::CloseOnTimeout, this); 0868 notification->setTitle(i18n("Failed to create hotspot %1", watcher->property("connection").toString())); 0869 break; 0870 default: 0871 break; 0872 } 0873 0874 if (notification) { 0875 notification->setComponentName(QStringLiteral("networkmanagement")); 0876 notification->setText(error); 0877 notification->setIconName(QStringLiteral("dialog-warning")); 0878 notification->sendEvent(); 0879 } 0880 } else { 0881 KNotification *notification = nullptr; 0882 Handler::HandlerAction action = (Handler::HandlerAction)watcher->property("action").toUInt(); 0883 0884 switch (action) { 0885 case Handler::AddConnection: 0886 notification = new KNotification(QStringLiteral("ConnectionAdded"), KNotification::CloseOnTimeout, this); 0887 notification->setText(i18n("Connection %1 has been added", watcher->property("connection").toString())); 0888 break; 0889 case Handler::RemoveConnection: 0890 notification = new KNotification(QStringLiteral("ConnectionRemoved"), KNotification::CloseOnTimeout, this); 0891 notification->setText(i18n("Connection %1 has been removed", watcher->property("connection").toString())); 0892 break; 0893 case Handler::UpdateConnection: 0894 notification = new KNotification(QStringLiteral("ConnectionUpdated"), KNotification::CloseOnTimeout, this); 0895 notification->setText(i18n("Connection %1 has been updated", watcher->property("connection").toString())); 0896 break; 0897 case Handler::RequestScan: 0898 qCDebug(PLASMA_NM_LIBS_LOG) << "Wireless scan on" << watcher->property("interface").toString() << "succeeded"; 0899 decrementScansCount(); 0900 break; 0901 default: 0902 break; 0903 } 0904 0905 if (notification) { 0906 notification->setComponentName(QStringLiteral("networkmanagement")); 0907 notification->setTitle(watcher->property("connection").toString()); 0908 notification->setIconName(QStringLiteral("dialog-information")); 0909 notification->sendEvent(); 0910 } 0911 } 0912 0913 watcher->deleteLater(); 0914 } 0915 0916 void Handler::hotspotCreated(QDBusPendingCallWatcher *watcher) 0917 { 0918 QDBusPendingReply<QDBusObjectPath, QDBusObjectPath, QVariantMap> reply = *watcher; 0919 0920 if (!reply.isError() && reply.isValid()) { 0921 const QString activeConnectionPath = reply.argumentAt(1).value<QDBusObjectPath>().path(); 0922 0923 if (activeConnectionPath.isEmpty()) { 0924 return; 0925 } 0926 0927 Configuration::self().setHotspotConnectionPath(activeConnectionPath); 0928 0929 NetworkManager::ActiveConnection::Ptr hotspot = NetworkManager::findActiveConnection(activeConnectionPath); 0930 0931 if (!hotspot) { 0932 return; 0933 } 0934 0935 connect(hotspot.data(), &NetworkManager::ActiveConnection::stateChanged, [=](NetworkManager::ActiveConnection::State state) { 0936 if (state > NetworkManager::ActiveConnection::Activated) { 0937 Configuration::self().setHotspotConnectionPath(QString()); 0938 Q_EMIT hotspotDisabled(); 0939 } 0940 }); 0941 0942 Q_EMIT hotspotCreated(); 0943 } 0944 } 0945 0946 void Handler::primaryConnectionTypeChanged(NetworkManager::ConnectionSettings::ConnectionType type) 0947 { 0948 Q_UNUSED(type) 0949 m_hotspotSupported = checkHotspotSupported(); 0950 Q_EMIT hotspotSupportedChanged(m_hotspotSupported); 0951 } 0952 0953 void Handler::unlockRequiredChanged(MMModemLock modemLock) 0954 { 0955 if (modemLock == MM_MODEM_LOCK_NONE) { 0956 activateConnection(m_tmpConnectionPath, m_tmpDevicePath, m_tmpSpecificPath); 0957 } 0958 } 0959 0960 void Handler::slotRequestWifiCode(QDBusPendingCallWatcher *watcher) 0961 { 0962 watcher->deleteLater(); 0963 0964 QString ret = watcher->property("ret").toString(); 0965 const QString connectionName = watcher->property("connectionName").toString(); 0966 QDBusPendingReply<NMVariantMapMap> reply = *watcher; 0967 if (!reply.isValid() || reply.isError()) { 0968 Q_EMIT wifiCodeReceived(ret % QLatin1Char(';'), connectionName); 0969 return; 0970 } 0971 0972 const auto secret = reply.argumentAt<0>()[watcher->property("key").toString()]; 0973 QString pass; 0974 switch (static_cast<NetworkManager::WirelessSecurityType>(watcher->property("securityType").toInt())) { 0975 case NetworkManager::NoneSecurity: 0976 break; 0977 case NetworkManager::WpaPsk: 0978 case NetworkManager::Wpa2Psk: 0979 case NetworkManager::SAE: 0980 pass = secret[QStringLiteral("psk")].toString(); 0981 break; 0982 default: 0983 Q_EMIT wifiCodeReceived(QString(), connectionName); 0984 return; 0985 } 0986 if (!pass.isEmpty()) { 0987 ret += QStringLiteral("P:") % pass % QLatin1Char(';'); 0988 } 0989 0990 Q_EMIT wifiCodeReceived(ret % QLatin1Char(';'), connectionName); 0991 }