File indexing completed on 2024-12-08 13:24:51
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 KWindowSystem::forceActiveWindow(editor->winId()); 0305 connect(editor.data(), &ConnectionEditorDialog::accepted, [editor, device, specificObject, this]() { // 0306 addAndActivateConnectionDBus(editor->setting(), device, specificObject); 0307 }); 0308 editor->setModal(true); 0309 editor->show(); 0310 } else { 0311 if (securityType == NetworkManager::StaticWep) { 0312 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep); 0313 wifiSecurity->setWepKey0(password); 0314 } else { 0315 if (ap->mode() == NetworkManager::AccessPoint::Adhoc) { 0316 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone); 0317 } else if (securityType == NetworkManager::SAE) { 0318 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::SAE); 0319 } else { 0320 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); 0321 } 0322 wifiSecurity->setPsk(password); 0323 } 0324 addAndActivateConnectionDBus(settings->toMap(), device, specificObject); 0325 } 0326 0327 settings.clear(); 0328 } 0329 0330 void Handler::addConnection(const NMVariantMapMap &map) 0331 { 0332 QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addConnection(map); 0333 auto watcher = new QDBusPendingCallWatcher(reply, this); 0334 watcher->setProperty("action", AddConnection); 0335 watcher->setProperty("connection", map.value(QStringLiteral("connection")).value(QStringLiteral("id"))); 0336 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0337 } 0338 0339 struct AddConnectionData { 0340 QString id; 0341 Handler *handler; 0342 }; 0343 0344 void add_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data) 0345 { 0346 AddConnectionData *data = static_cast<AddConnectionData *>(user_data); 0347 0348 GError *error = nullptr; 0349 NMRemoteConnection *connection = nm_client_add_connection2_finish(NM_CLIENT(client), result, NULL, &error); 0350 0351 if (error) { 0352 KNotification *notification = new KNotification(QStringLiteral("FailedToAddConnection"), KNotification::CloseOnTimeout, data->handler); 0353 notification->setTitle(i18n("Failed to add connection %1", data->id)); 0354 notification->setComponentName(QStringLiteral("networkmanagement")); 0355 notification->setText(QString::fromUtf8(error->message)); 0356 notification->setIconName(QStringLiteral("dialog-warning")); 0357 notification->sendEvent(); 0358 0359 g_error_free(error); 0360 } else { 0361 KNotification *notification = new KNotification(QStringLiteral("ConnectionAdded"), KNotification::CloseOnTimeout, data->handler); 0362 notification->setText(i18n("Connection %1 has been added", data->id)); 0363 notification->setComponentName(QStringLiteral("networkmanagement")); 0364 notification->setTitle(data->id); 0365 notification->setIconName(QStringLiteral("dialog-information")); 0366 notification->sendEvent(); 0367 0368 g_object_unref(connection); 0369 } 0370 0371 delete data; 0372 } 0373 0374 void Handler::addConnection(NMConnection *connection) 0375 { 0376 NMClient *client = nm_client_new(nullptr, nullptr); 0377 0378 AddConnectionData *userData = new AddConnectionData{QString::fromUtf8(nm_connection_get_id(connection)), this}; 0379 0380 nm_client_add_connection2(client, 0381 nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL), 0382 NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK, 0383 nullptr, 0384 true, 0385 nullptr, 0386 add_connection_cb, 0387 userData); 0388 } 0389 0390 void Handler::addAndActivateConnectionDBus(const NMVariantMapMap &map, const QString &device, const QString &specificObject) 0391 { 0392 QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addAndActivateConnection(map, device, specificObject); 0393 auto watcher = new QDBusPendingCallWatcher(reply, this); 0394 watcher->setProperty("action", AddAndActivateConnection); 0395 watcher->setProperty("connection", map.value(QStringLiteral("connection")).value(QStringLiteral("id"))); 0396 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0397 } 0398 0399 void Handler::deactivateConnection(const QString &connection, const QString &device) 0400 { 0401 NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); 0402 0403 if (!con) { 0404 qCWarning(PLASMA_NM_LIBS_LOG) << "Not possible to deactivate this connection"; 0405 return; 0406 } 0407 0408 QDBusPendingReply<> reply; 0409 for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) { 0410 if (active->uuid() == con->uuid() && ((!active->devices().isEmpty() && active->devices().first() == device) || active->vpn())) { 0411 if (active->vpn()) { 0412 reply = NetworkManager::deactivateConnection(active->path()); 0413 } else { 0414 NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first()); 0415 if (device) { 0416 reply = device->disconnectInterface(); 0417 } 0418 } 0419 } 0420 } 0421 0422 auto watcher = new QDBusPendingCallWatcher(reply, this); 0423 watcher->setProperty("action", Handler::DeactivateConnection); 0424 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0425 } 0426 0427 void Handler::disconnectAll() 0428 { 0429 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0430 device->disconnectInterface(); 0431 } 0432 } 0433 0434 void Handler::enableAirplaneMode(bool enable) 0435 { 0436 if (enable) { 0437 m_tmpWirelessEnabled = NetworkManager::isWirelessEnabled(); 0438 m_tmpWwanEnabled = NetworkManager::isWwanEnabled(); 0439 enableBluetooth(false); 0440 enableWireless(false); 0441 enableWwan(false); 0442 } else { 0443 enableBluetooth(true); 0444 if (m_tmpWirelessEnabled) { 0445 enableWireless(true); 0446 } 0447 if (m_tmpWwanEnabled) { 0448 enableWwan(true); 0449 } 0450 } 0451 } 0452 0453 template<typename T> 0454 void makeDBusCall(const QDBusMessage &message, QObject *context, std::function<void(QDBusPendingReply<T>)> func) 0455 { 0456 QDBusPendingReply<T> reply = QDBusConnection::systemBus().asyncCall(message); 0457 auto watcher = new QDBusPendingCallWatcher(reply, context); 0458 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, context, [func](QDBusPendingCallWatcher *watcher) { 0459 const QDBusPendingReply<T> reply = *watcher; 0460 if (!reply.isValid()) { 0461 qCWarning(PLASMA_NM_LIBS_LOG) << reply.error().message(); 0462 return; 0463 } 0464 func(reply); 0465 watcher->deleteLater(); 0466 }); 0467 } 0468 0469 void setBluetoothEnabled(const QString &path, bool enabled) 0470 { 0471 QDBusMessage message = 0472 QDBusMessage::createMethodCall(QStringLiteral("org.bluez"), path, QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("Set")); 0473 QList<QVariant> arguments; 0474 arguments << QLatin1String("org.bluez.Adapter1"); 0475 arguments << QLatin1String("Powered"); 0476 arguments << QVariant::fromValue(QDBusVariant(QVariant(enabled))); 0477 message.setArguments(arguments); 0478 QDBusConnection::systemBus().asyncCall(message); 0479 } 0480 0481 void Handler::enableBluetooth(bool enable) 0482 { 0483 qDBusRegisterMetaType<QMap<QDBusObjectPath, NMVariantMapMap>>(); 0484 0485 const QDBusMessage getObjects = QDBusMessage::createMethodCall("org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 0486 0487 makeDBusCall<QMap<QDBusObjectPath, NMVariantMapMap>>(getObjects, this, [enable, this](const auto reply) { 0488 for (const QDBusObjectPath &path : reply.value().keys()) { 0489 const QString objPath = path.path(); 0490 qCDebug(PLASMA_NM_LIBS_LOG) << "inspecting path" << objPath; 0491 const QStringList interfaces = reply.value().value(path).keys(); 0492 qCDebug(PLASMA_NM_LIBS_LOG) << "interfaces:" << interfaces; 0493 0494 if (!interfaces.contains(QStringLiteral("org.bluez.Adapter1"))) { 0495 continue; 0496 } 0497 0498 // We need to check previous state first 0499 if (!enable) { 0500 QDBusMessage getPowered = QDBusMessage::createMethodCall("org.bluez", objPath, "org.freedesktop.DBus.Properties", "Get"); 0501 const QList<QVariant> arguments{QLatin1String("org.bluez.Adapter1"), QLatin1String("Powered")}; 0502 getPowered.setArguments(arguments); 0503 0504 makeDBusCall<QVariant>(getPowered, this, [objPath, this](const auto reply) { 0505 m_bluetoothAdapters.insert(objPath, reply.value().toBool()); 0506 setBluetoothEnabled(objPath, false); 0507 }); 0508 } else if (m_bluetoothAdapters.value(objPath)) { 0509 setBluetoothEnabled(objPath, true); 0510 } 0511 } 0512 }); 0513 } 0514 0515 void Handler::enableNetworking(bool enable) 0516 { 0517 NetworkManager::setNetworkingEnabled(enable); 0518 } 0519 0520 void Handler::enableWireless(bool enable) 0521 { 0522 NetworkManager::setWirelessEnabled(enable); 0523 } 0524 0525 void Handler::enableWwan(bool enable) 0526 { 0527 NetworkManager::setWwanEnabled(enable); 0528 } 0529 0530 void Handler::removeConnection(const QString &connection) 0531 { 0532 NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); 0533 0534 if (!con || con->uuid().isEmpty()) { 0535 qCWarning(PLASMA_NM_LIBS_LOG) << "Not possible to remove connection " << connection; 0536 return; 0537 } 0538 0539 // Remove slave connections 0540 for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) { 0541 NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); 0542 if (settings->master() == con->uuid()) { 0543 connection->remove(); 0544 } 0545 } 0546 0547 QDBusPendingReply<> reply = con->remove(); 0548 auto watcher = new QDBusPendingCallWatcher(reply, this); 0549 watcher->setProperty("action", Handler::RemoveConnection); 0550 watcher->setProperty("connection", con->name()); 0551 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0552 } 0553 0554 void Handler::updateConnection(const NetworkManager::Connection::Ptr &connection, const NMVariantMapMap &map) 0555 { 0556 QDBusPendingReply<> reply = connection->update(map); 0557 auto watcher = new QDBusPendingCallWatcher(reply, this); 0558 watcher->setProperty("action", UpdateConnection); 0559 watcher->setProperty("connection", connection->name()); 0560 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0561 } 0562 0563 void Handler::requestScan(const QString &interface) 0564 { 0565 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0566 if (device->type() == NetworkManager::Device::Wifi) { 0567 NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>(); 0568 0569 if (wifiDevice && wifiDevice->state() != NetworkManager::WirelessDevice::Unavailable) { 0570 if (!interface.isEmpty() && interface != wifiDevice->interfaceName()) { 0571 continue; 0572 } 0573 0574 if (!checkRequestScanRateLimit(wifiDevice)) { 0575 QDateTime now = QDateTime::currentDateTime(); 0576 // for NM < 1.12, lastScan is not available 0577 QDateTime lastScan = wifiDevice->lastScan(); 0578 QDateTime lastRequestScan = wifiDevice->lastRequestScan(); 0579 // Compute the next time we can run a scan 0580 int timeout = NM_REQUESTSCAN_LIMIT_RATE; 0581 if (lastScan.isValid() && lastScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE) { 0582 timeout = NM_REQUESTSCAN_LIMIT_RATE - lastScan.msecsTo(now); 0583 } else if (lastRequestScan.isValid() && lastRequestScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE) { 0584 timeout = NM_REQUESTSCAN_LIMIT_RATE - lastRequestScan.msecsTo(now); 0585 } 0586 qCDebug(PLASMA_NM_LIBS_LOG) << "Rescheduling a request scan for" << wifiDevice->interfaceName() << "in" << timeout; 0587 scheduleRequestScan(wifiDevice->interfaceName(), timeout); 0588 0589 if (!interface.isEmpty()) { 0590 return; 0591 } 0592 continue; 0593 } else if (m_wirelessScanRetryTimer.contains(interface)) { 0594 m_wirelessScanRetryTimer.value(interface)->stop(); 0595 delete m_wirelessScanRetryTimer.take(interface); 0596 } 0597 0598 qCDebug(PLASMA_NM_LIBS_LOG) << "Requesting wifi scan on device" << wifiDevice->interfaceName(); 0599 incrementScansCount(); 0600 QDBusPendingReply<> reply = wifiDevice->requestScan(); 0601 auto watcher = new QDBusPendingCallWatcher(reply, this); 0602 watcher->setProperty("action", Handler::RequestScan); 0603 watcher->setProperty("interface", wifiDevice->interfaceName()); 0604 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0605 } 0606 } 0607 } 0608 } 0609 0610 void Handler::incrementScansCount() 0611 { 0612 m_ongoingScansCount += 1; 0613 if (m_ongoingScansCount == 1) { 0614 Q_EMIT scanningChanged(); 0615 } 0616 } 0617 0618 void Handler::decrementScansCount() 0619 { 0620 if (m_ongoingScansCount == 0) { 0621 qCDebug(PLASMA_NM_LIBS_LOG) << "Extra decrementScansCount() called"; 0622 return; 0623 } 0624 m_ongoingScansCount -= 1; 0625 if (m_ongoingScansCount == 0) { 0626 Q_EMIT scanningChanged(); 0627 } 0628 } 0629 0630 void Handler::createHotspot() 0631 { 0632 bool foundInactive = false; 0633 bool useApMode = false; 0634 NetworkManager::WirelessDevice::Ptr wifiDev; 0635 0636 NetworkManager::ConnectionSettings::Ptr connectionSettings; 0637 connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); 0638 0639 NetworkManager::WirelessSetting::Ptr wifiSetting = 0640 connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>(); 0641 wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); 0642 wifiSetting->setSsid(Configuration::self().hotspotName().toUtf8()); 0643 0644 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0645 if (device->type() == NetworkManager::Device::Wifi) { 0646 wifiDev = device.objectCast<NetworkManager::WirelessDevice>(); 0647 if (wifiDev) { 0648 if (!wifiDev->isActive()) { 0649 foundInactive = true; 0650 } else { 0651 // Prefer previous device if it was inactive 0652 if (foundInactive) { 0653 break; 0654 } 0655 } 0656 0657 if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { 0658 useApMode = true; 0659 } 0660 0661 // We prefer inactive wireless card with AP capabilities 0662 if (foundInactive && useApMode) { 0663 break; 0664 } 0665 } 0666 } 0667 } 0668 0669 if (!wifiDev) { 0670 qCWarning(PLASMA_NM_LIBS_LOG) << "Failed to create hotspot: missing wireless device"; 0671 return; 0672 } 0673 0674 wifiSetting->setInitialized(true); 0675 wifiSetting->setMode(useApMode ? NetworkManager::WirelessSetting::Ap : NetworkManager::WirelessSetting::Adhoc); 0676 0677 if (!Configuration::self().hotspotPassword().isEmpty()) { 0678 NetworkManager::WirelessSecuritySetting::Ptr wifiSecurity = 0679 connectionSettings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast<NetworkManager::WirelessSecuritySetting>(); 0680 wifiSecurity->setInitialized(true); 0681 0682 if (useApMode) { 0683 // Use WPA2 0684 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); 0685 wifiSecurity->setPsk(Configuration::self().hotspotPassword()); 0686 wifiSecurity->setPskFlags(NetworkManager::Setting::AgentOwned); 0687 } else { 0688 // Use WEP 0689 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep); 0690 wifiSecurity->setWepKeyType(NetworkManager::WirelessSecuritySetting::Passphrase); 0691 wifiSecurity->setWepTxKeyindex(0); 0692 wifiSecurity->setWepKey0(Configuration::self().hotspotPassword()); 0693 wifiSecurity->setWepKeyFlags(NetworkManager::Setting::AgentOwned); 0694 wifiSecurity->setAuthAlg(NetworkManager::WirelessSecuritySetting::Open); 0695 } 0696 } 0697 0698 NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast<NetworkManager::Ipv4Setting>(); 0699 ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Shared); 0700 ipv4Setting->setInitialized(true); 0701 0702 connectionSettings->setId(Configuration::self().hotspotName()); 0703 connectionSettings->setAutoconnect(false); 0704 connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); 0705 0706 const QVariantMap options = {{QLatin1String("persist"), QLatin1String("volatile")}}; 0707 0708 QDBusPendingReply<QDBusObjectPath, QDBusObjectPath, QVariantMap> reply = 0709 NetworkManager::addAndActivateConnection2(connectionSettings->toMap(), wifiDev->uni(), QString(), options); 0710 auto watcher = new QDBusPendingCallWatcher(reply, this); 0711 watcher->setProperty("action", Handler::CreateHotspot); 0712 watcher->setProperty("connection", Configuration::self().hotspotName()); 0713 connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); 0714 connect(watcher, &QDBusPendingCallWatcher::finished, this, QOverload<QDBusPendingCallWatcher *>::of(&Handler::hotspotCreated)); 0715 } 0716 0717 void Handler::stopHotspot() 0718 { 0719 const QString activeConnectionPath = Configuration::self().hotspotConnectionPath(); 0720 0721 if (activeConnectionPath.isEmpty()) { 0722 return; 0723 } 0724 0725 NetworkManager::ActiveConnection::Ptr hotspot = NetworkManager::findActiveConnection(activeConnectionPath); 0726 0727 if (!hotspot) { 0728 return; 0729 } 0730 0731 NetworkManager::deactivateConnection(activeConnectionPath); 0732 Configuration::self().setHotspotConnectionPath(QString()); 0733 0734 Q_EMIT hotspotDisabled(); 0735 } 0736 0737 bool Handler::checkRequestScanRateLimit(const NetworkManager::WirelessDevice::Ptr &wifiDevice) 0738 { 0739 QDateTime now = QDateTime::currentDateTime(); 0740 QDateTime lastScan = wifiDevice->lastScan(); 0741 QDateTime lastRequestScan = wifiDevice->lastRequestScan(); 0742 0743 // if the last scan finished within the last 10 seconds 0744 bool ret = lastScan.isValid() && lastScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE; 0745 // or if the last Request was sent within the last 10 seconds 0746 ret |= lastRequestScan.isValid() && lastRequestScan.msecsTo(now) < NM_REQUESTSCAN_LIMIT_RATE; 0747 // skip the request scan 0748 if (ret) { 0749 qCDebug(PLASMA_NM_LIBS_LOG) << "Last scan finished" << lastScan.msecsTo(now) << "ms ago and last request scan was sent" // 0750 << lastRequestScan.msecsTo(now) << "ms ago, Skipping scanning interface:" << wifiDevice->interfaceName(); 0751 return false; 0752 } 0753 return true; 0754 } 0755 0756 bool Handler::checkHotspotSupported() 0757 { 0758 if (NetworkManager::checkVersion(1, 16, 0)) { 0759 bool unusedWifiFound = false; 0760 bool wifiFound = false; 0761 0762 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0763 if (device->type() == NetworkManager::Device::Wifi) { 0764 wifiFound = true; 0765 0766 NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast<NetworkManager::WirelessDevice>(); 0767 if (wifiDev && !wifiDev->isActive()) { 0768 unusedWifiFound = true; 0769 } 0770 } 0771 } 0772 0773 if (!wifiFound) { 0774 return false; 0775 } 0776 0777 if (unusedWifiFound) { 0778 return true; 0779 } 0780 0781 // Check if the primary connection which is used for internet connectivity is not using WiFi 0782 if (NetworkManager::primaryConnectionType() != NetworkManager::ConnectionSettings::Wireless) { 0783 return true; 0784 } 0785 } 0786 0787 return false; 0788 } 0789 0790 void Handler::scheduleRequestScan(const QString &interface, int timeout) 0791 { 0792 QTimer *timer; 0793 if (!m_wirelessScanRetryTimer.contains(interface)) { 0794 // create a timer for the interface 0795 timer = new QTimer(); 0796 timer->setSingleShot(true); 0797 m_wirelessScanRetryTimer.insert(interface, timer); 0798 auto retryAction = [this, interface]() { 0799 requestScan(interface); 0800 }; 0801 connect(timer, &QTimer::timeout, this, retryAction); 0802 } else { 0803 // set the new value for an existing timer 0804 timer = m_wirelessScanRetryTimer.value(interface); 0805 if (timer->isActive()) { 0806 timer->stop(); 0807 } 0808 } 0809 0810 // +1 ms is added to avoid having the scan being rejetted by nm 0811 // because it is run at the exact last millisecond of the requestScan threshold 0812 timer->setInterval(timeout + 1); 0813 timer->start(); 0814 } 0815 0816 void Handler::scanRequestFailed(const QString &interface) 0817 { 0818 scheduleRequestScan(interface, 2000); 0819 } 0820 0821 void Handler::secretAgentError(const QString &connectionPath, const QString &message) 0822 { 0823 // If the password was wrong, forget it 0824 removeConnection(connectionPath); 0825 Q_EMIT connectionActivationFailed(connectionPath, message); 0826 } 0827 0828 void Handler::replyFinished(QDBusPendingCallWatcher *watcher) 0829 { 0830 QDBusPendingReply<> reply = *watcher; 0831 if (reply.isError() || !reply.isValid()) { 0832 KNotification *notification = nullptr; 0833 QString error = reply.error().message(); 0834 Handler::HandlerAction action = (Handler::HandlerAction)watcher->property("action").toUInt(); 0835 switch (action) { 0836 case Handler::ActivateConnection: 0837 notification = new KNotification(QStringLiteral("FailedToActivateConnection"), KNotification::CloseOnTimeout, this); 0838 notification->setTitle(i18n("Failed to activate %1", watcher->property("connection").toString())); 0839 break; 0840 case Handler::AddAndActivateConnection: 0841 notification = new KNotification(QStringLiteral("FailedToAddConnection"), KNotification::CloseOnTimeout, this); 0842 notification->setTitle(i18n("Failed to add %1", watcher->property("connection").toString())); 0843 break; 0844 case Handler::AddConnection: 0845 notification = new KNotification(QStringLiteral("FailedToAddConnection"), KNotification::CloseOnTimeout, this); 0846 notification->setTitle(i18n("Failed to add connection %1", watcher->property("connection").toString())); 0847 break; 0848 case Handler::DeactivateConnection: 0849 notification = new KNotification(QStringLiteral("FailedToDeactivateConnection"), KNotification::CloseOnTimeout, this); 0850 notification->setTitle(i18n("Failed to deactivate %1", watcher->property("connection").toString())); 0851 break; 0852 case Handler::RemoveConnection: 0853 notification = new KNotification(QStringLiteral("FailedToRemoveConnection"), KNotification::CloseOnTimeout, this); 0854 notification->setTitle(i18n("Failed to remove %1", watcher->property("connection").toString())); 0855 break; 0856 case Handler::UpdateConnection: 0857 notification = new KNotification(QStringLiteral("FailedToUpdateConnection"), KNotification::CloseOnTimeout, this); 0858 notification->setTitle(i18n("Failed to update connection %1", watcher->property("connection").toString())); 0859 break; 0860 case Handler::RequestScan: { 0861 const QString interface = watcher->property("interface").toString(); 0862 qCWarning(PLASMA_NM_LIBS_LOG) << "Wireless scan on" << interface << "failed:" << error; 0863 scanRequestFailed(interface); 0864 decrementScansCount(); 0865 break; 0866 } 0867 case Handler::CreateHotspot: 0868 notification = new KNotification(QStringLiteral("FailedToCreateHotspot"), KNotification::CloseOnTimeout, this); 0869 notification->setTitle(i18n("Failed to create hotspot %1", watcher->property("connection").toString())); 0870 break; 0871 default: 0872 break; 0873 } 0874 0875 if (notification) { 0876 notification->setComponentName(QStringLiteral("networkmanagement")); 0877 notification->setText(error); 0878 notification->setIconName(QStringLiteral("dialog-warning")); 0879 notification->sendEvent(); 0880 } 0881 } else { 0882 KNotification *notification = nullptr; 0883 Handler::HandlerAction action = (Handler::HandlerAction)watcher->property("action").toUInt(); 0884 0885 switch (action) { 0886 case Handler::AddConnection: 0887 notification = new KNotification(QStringLiteral("ConnectionAdded"), KNotification::CloseOnTimeout, this); 0888 notification->setText(i18n("Connection %1 has been added", watcher->property("connection").toString())); 0889 break; 0890 case Handler::RemoveConnection: 0891 notification = new KNotification(QStringLiteral("ConnectionRemoved"), KNotification::CloseOnTimeout, this); 0892 notification->setText(i18n("Connection %1 has been removed", watcher->property("connection").toString())); 0893 break; 0894 case Handler::UpdateConnection: 0895 notification = new KNotification(QStringLiteral("ConnectionUpdated"), KNotification::CloseOnTimeout, this); 0896 notification->setText(i18n("Connection %1 has been updated", watcher->property("connection").toString())); 0897 break; 0898 case Handler::RequestScan: 0899 qCDebug(PLASMA_NM_LIBS_LOG) << "Wireless scan on" << watcher->property("interface").toString() << "succeeded"; 0900 decrementScansCount(); 0901 break; 0902 default: 0903 break; 0904 } 0905 0906 if (notification) { 0907 notification->setComponentName(QStringLiteral("networkmanagement")); 0908 notification->setTitle(watcher->property("connection").toString()); 0909 notification->setIconName(QStringLiteral("dialog-information")); 0910 notification->sendEvent(); 0911 } 0912 } 0913 0914 watcher->deleteLater(); 0915 } 0916 0917 void Handler::hotspotCreated(QDBusPendingCallWatcher *watcher) 0918 { 0919 QDBusPendingReply<QDBusObjectPath, QDBusObjectPath, QVariantMap> reply = *watcher; 0920 0921 if (!reply.isError() && reply.isValid()) { 0922 const QString activeConnectionPath = reply.argumentAt(1).value<QDBusObjectPath>().path(); 0923 0924 if (activeConnectionPath.isEmpty()) { 0925 return; 0926 } 0927 0928 Configuration::self().setHotspotConnectionPath(activeConnectionPath); 0929 0930 NetworkManager::ActiveConnection::Ptr hotspot = NetworkManager::findActiveConnection(activeConnectionPath); 0931 0932 if (!hotspot) { 0933 return; 0934 } 0935 0936 connect(hotspot.data(), &NetworkManager::ActiveConnection::stateChanged, [=](NetworkManager::ActiveConnection::State state) { 0937 if (state > NetworkManager::ActiveConnection::Activated) { 0938 Configuration::self().setHotspotConnectionPath(QString()); 0939 Q_EMIT hotspotDisabled(); 0940 } 0941 }); 0942 0943 Q_EMIT hotspotCreated(); 0944 } 0945 } 0946 0947 void Handler::primaryConnectionTypeChanged(NetworkManager::ConnectionSettings::ConnectionType type) 0948 { 0949 Q_UNUSED(type) 0950 m_hotspotSupported = checkHotspotSupported(); 0951 Q_EMIT hotspotSupportedChanged(m_hotspotSupported); 0952 } 0953 0954 void Handler::unlockRequiredChanged(MMModemLock modemLock) 0955 { 0956 if (modemLock == MM_MODEM_LOCK_NONE) { 0957 activateConnection(m_tmpConnectionPath, m_tmpDevicePath, m_tmpSpecificPath); 0958 } 0959 } 0960 0961 void Handler::slotRequestWifiCode(QDBusPendingCallWatcher *watcher) 0962 { 0963 watcher->deleteLater(); 0964 0965 QString ret = watcher->property("ret").toString(); 0966 const QString connectionName = watcher->property("connectionName").toString(); 0967 QDBusPendingReply<NMVariantMapMap> reply = *watcher; 0968 if (!reply.isValid() || reply.isError()) { 0969 Q_EMIT wifiCodeReceived(ret % QLatin1Char(';'), connectionName); 0970 return; 0971 } 0972 0973 const auto secret = reply.argumentAt<0>()[watcher->property("key").toString()]; 0974 QString pass; 0975 switch (static_cast<NetworkManager::WirelessSecurityType>(watcher->property("securityType").toInt())) { 0976 case NetworkManager::NoneSecurity: 0977 break; 0978 case NetworkManager::WpaPsk: 0979 case NetworkManager::Wpa2Psk: 0980 case NetworkManager::SAE: 0981 pass = secret[QStringLiteral("psk")].toString(); 0982 break; 0983 default: 0984 Q_EMIT wifiCodeReceived(QString(), connectionName); 0985 return; 0986 } 0987 if (!pass.isEmpty()) { 0988 ret += QStringLiteral("P:") % pass % QLatin1Char(';'); 0989 } 0990 0991 Q_EMIT wifiCodeReceived(ret % QLatin1Char(';'), connectionName); 0992 }