File indexing completed on 2024-10-06 10:58:14
0001 /* 0002 SPDX-FileCopyrightText: 2016 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 "kcm.h" 0008 0009 #include "configuration.h" 0010 #include "connectioneditordialog.h" 0011 #include "mobileconnectionwizard.h" 0012 #include "plasma_nm_kcm.h" 0013 #include "settings/wireguardinterfacewidget.h" 0014 #include "uiutils.h" 0015 #include "vpnuiplugin.h" 0016 0017 // KDE 0018 #include <KLocalizedContext> 0019 #include <KMessageBox> 0020 #include <KMessageWidget> 0021 #include <KPluginFactory> 0022 #include <KPluginMetaData> 0023 #include <KSharedConfig> 0024 #include <kwidgetsaddons_version.h> 0025 0026 #include <NetworkManagerQt/ActiveConnection> 0027 #include <NetworkManagerQt/Connection> 0028 #include <NetworkManagerQt/ConnectionSettings> 0029 #include <NetworkManagerQt/GsmSetting> 0030 #include <NetworkManagerQt/Ipv4Setting> 0031 #include <NetworkManagerQt/Ipv6Setting> 0032 #include <NetworkManagerQt/Settings> 0033 #include <NetworkManagerQt/Utils> 0034 #include <NetworkManagerQt/VpnSetting> 0035 #include <NetworkManagerQt/WiredSetting> 0036 #include <NetworkManagerQt/WireguardSetting> 0037 #include <NetworkManagerQt/WirelessDevice> 0038 #include <NetworkManagerQt/WirelessSetting> 0039 0040 // Qt 0041 #include <QFileDialog> 0042 #include <QMenu> 0043 #include <QQmlContext> 0044 #include <QQmlEngine> 0045 #include <QQuickItem> 0046 #include <QQuickView> 0047 #include <QQuickWidget> 0048 #include <QStringBuilder> 0049 #include <QTimer> 0050 #include <QVBoxLayout> 0051 0052 K_PLUGIN_CLASS_WITH_JSON(KCMNetworkmanagement, "kcm_networkmanagement.json") 0053 0054 KCMNetworkmanagement::KCMNetworkmanagement(QWidget *parent, const QVariantList &args) 0055 : KCModule(parent, args) 0056 , m_handler(new Handler(this)) 0057 , m_ui(new Ui::KCMForm) 0058 { 0059 auto mainWidget = new QWidget(this); 0060 m_ui->setupUi(mainWidget); 0061 0062 KLocalizedContext *l10nContext = new KLocalizedContext(m_ui->connectionView->engine()); 0063 l10nContext->setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN)); 0064 m_ui->connectionView->engine()->rootContext()->setContextObject(l10nContext); 0065 0066 // Check if we can use AP mode to identify security type 0067 bool useApMode = false; 0068 bool foundInactive = false; 0069 0070 NetworkManager::WirelessDevice::Ptr wifiDev; 0071 0072 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0073 if (device->type() == NetworkManager::Device::Wifi) { 0074 wifiDev = device.objectCast<NetworkManager::WirelessDevice>(); 0075 if (wifiDev) { 0076 if (!wifiDev->isActive()) { 0077 foundInactive = true; 0078 } else { 0079 // Prefer previous device if it was inactive 0080 if (foundInactive) { 0081 break; 0082 } 0083 } 0084 0085 if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { 0086 useApMode = true; 0087 } 0088 0089 // We prefer inactive wireless card with AP capabilities 0090 if (foundInactive && useApMode) { 0091 break; 0092 } 0093 } 0094 } 0095 } 0096 0097 m_ui->connectionView->setMinimumWidth(300); 0098 m_ui->connectionView->rootContext()->setContextProperty("alternateBaseColor", mainWidget->palette().color(QPalette::Active, QPalette::AlternateBase)); 0099 m_ui->connectionView->rootContext()->setContextProperty("backgroundColor", mainWidget->palette().color(QPalette::Active, QPalette::Window)); 0100 m_ui->connectionView->rootContext()->setContextProperty("baseColor", mainWidget->palette().color(QPalette::Active, QPalette::Base)); 0101 m_ui->connectionView->rootContext()->setContextProperty("highlightColor", mainWidget->palette().color(QPalette::Active, QPalette::Highlight)); 0102 m_ui->connectionView->rootContext()->setContextProperty("textColor", mainWidget->palette().color(QPalette::Active, QPalette::Text)); 0103 m_ui->connectionView->rootContext()->setContextProperty("connectionModified", false); 0104 m_ui->connectionView->rootContext()->setContextProperty("useApMode", useApMode); 0105 m_ui->connectionView->setClearColor(Qt::transparent); 0106 m_ui->connectionView->setResizeMode(QQuickWidget::SizeRootObjectToView); 0107 m_ui->connectionView->setSource( 0108 QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcm_networkmanagement/qml/main.qml")))); 0109 0110 QObject *rootItem = m_ui->connectionView->rootObject(); 0111 connect(rootItem, SIGNAL(selectedConnectionChanged(QString)), this, SLOT(onSelectedConnectionChanged(QString))); 0112 connect(rootItem, SIGNAL(requestCreateConnection(int, QString, QString, bool)), this, SLOT(onRequestCreateConnection(int, QString, QString, bool))); 0113 connect(rootItem, SIGNAL(requestExportConnection(QString)), this, SLOT(onRequestExportConnection(QString))); 0114 connect(rootItem, SIGNAL(requestToChangeConnection(QString, QString)), this, SLOT(onRequestToChangeConnection(QString, QString))); 0115 0116 auto l = new QVBoxLayout(this); 0117 0118 m_errorWidget = new KMessageWidget(this); 0119 m_errorWidget->setVisible(false); 0120 m_errorWidget->setMessageType(KMessageWidget::Error); 0121 l->addWidget(m_errorWidget); 0122 0123 l->addWidget(mainWidget); 0124 0125 setButtons(Button::Apply); 0126 0127 NetworkManager::Connection::Ptr selectedConnection; 0128 0129 // Look in the arguments for a connection ID to preselect 0130 static const QLatin1String uuidArgumentMarker{"Uuid="}; 0131 for (QVariant arg : args) { 0132 if (arg.canConvert(QMetaType::QString)) { 0133 QString uuid = arg.toString(); 0134 if (uuid.startsWith(uuidArgumentMarker)) { 0135 uuid = uuid.replace(uuidArgumentMarker, QString()); 0136 selectedConnection = NetworkManager::findConnectionByUuid(uuid); 0137 qDebug(PLASMA_NM_KCM_LOG) << "Selecting user connection:" << uuid; 0138 break; 0139 } 0140 } 0141 } 0142 0143 // Pre-select the currently active primary connection 0144 if (!selectedConnection || !selectedConnection->isValid()) { 0145 NetworkManager::ActiveConnection::Ptr activeConnection = NetworkManager::primaryConnection(); 0146 if (activeConnection && activeConnection->isValid()) { 0147 selectedConnection = activeConnection->connection(); 0148 qDebug(PLASMA_NM_KCM_LOG) << "Selecting active connection:" << selectedConnection->uuid(); 0149 } 0150 } 0151 0152 // Select the very first connection as a fallback 0153 if (!selectedConnection || !selectedConnection->isValid()) { 0154 NetworkManager::Connection::List connectionList = NetworkManager::listConnections(); 0155 std::sort(connectionList.begin(), connectionList.end(), [](const NetworkManager::Connection::Ptr &left, const NetworkManager::Connection::Ptr &right) { 0156 const QString leftName = left->settings()->id(); 0157 const UiUtils::SortedConnectionType leftType = UiUtils::connectionTypeToSortedType(left->settings()->connectionType()); 0158 const QDateTime leftDate = left->settings()->timestamp(); 0159 0160 const QString rightName = right->settings()->id(); 0161 const UiUtils::SortedConnectionType rightType = UiUtils::connectionTypeToSortedType(right->settings()->connectionType()); 0162 const QDateTime rightDate = right->settings()->timestamp(); 0163 0164 if (leftType < rightType) { 0165 return true; 0166 } else if (leftType > rightType) { 0167 return false; 0168 } 0169 0170 if (leftDate > rightDate) { 0171 return true; 0172 } else if (leftDate < rightDate) { 0173 return false; 0174 } 0175 0176 if (QString::localeAwareCompare(leftName, rightName) > 0) { 0177 return true; 0178 } else { 0179 return false; 0180 } 0181 }); 0182 0183 for (const NetworkManager::Connection::Ptr &connection : connectionList) { 0184 const NetworkManager::ConnectionSettings::ConnectionType type = connection->settings()->connectionType(); 0185 if (UiUtils::isConnectionTypeSupported(type)) { 0186 selectedConnection = connection; 0187 qDebug(PLASMA_NM_KCM_LOG) << "Selecting first connection:" << connection->uuid(); 0188 break; 0189 } 0190 } 0191 } 0192 0193 if (selectedConnection && selectedConnection->isValid()) { 0194 const NetworkManager::ConnectionSettings::Ptr settings = selectedConnection->settings(); 0195 if (UiUtils::isConnectionTypeSupported(settings->connectionType())) { 0196 QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, settings->id()), Q_ARG(QVariant, selectedConnection->path())); 0197 } 0198 } else { 0199 qDebug(PLASMA_NM_KCM_LOG) << "Cannot preselect a connection"; 0200 } 0201 0202 connect(NetworkManager::settingsNotifier(), 0203 &NetworkManager::SettingsNotifier::connectionAdded, 0204 this, 0205 &KCMNetworkmanagement::onConnectionAdded, 0206 Qt::UniqueConnection); 0207 0208 // Initialize first scan and then scan every 15 seconds 0209 m_handler->requestScan(); 0210 0211 m_timer = new QTimer(this); 0212 m_timer->setInterval(15000); 0213 connect(m_timer, &QTimer::timeout, [this]() { 0214 m_handler->requestScan(); 0215 }); 0216 m_timer->start(); 0217 } 0218 0219 KCMNetworkmanagement::~KCMNetworkmanagement() 0220 { 0221 delete m_handler; 0222 delete m_ui; 0223 } 0224 0225 void KCMNetworkmanagement::defaults() 0226 { 0227 KCModule::defaults(); 0228 } 0229 0230 void KCMNetworkmanagement::load() 0231 { 0232 // If there is no loaded connection do nothing 0233 if (m_currentConnectionPath.isEmpty()) { 0234 return; 0235 } 0236 0237 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); 0238 if (connection) { 0239 NetworkManager::ConnectionSettings::Ptr connectionSettings = connection->settings(); 0240 // Re-load the connection again to load stored values 0241 if (m_tabWidget) { 0242 m_tabWidget->setConnection(connectionSettings); 0243 } 0244 } 0245 0246 KCModule::load(); 0247 } 0248 0249 void KCMNetworkmanagement::save() 0250 { 0251 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); 0252 0253 if (connection) { 0254 m_handler->updateConnection(connection, m_tabWidget->setting()); 0255 } 0256 0257 kcmChanged(false); 0258 0259 KCModule::save(); 0260 } 0261 0262 void KCMNetworkmanagement::onConnectionAdded(const QString &connection) 0263 { 0264 if (m_createdConnectionUuid.isEmpty()) { 0265 return; 0266 } 0267 0268 NetworkManager::Connection::Ptr newConnection = NetworkManager::findConnection(connection); 0269 if (newConnection) { 0270 NetworkManager::ConnectionSettings::Ptr connectionSettings = newConnection->settings(); 0271 if (connectionSettings && connectionSettings->uuid() == m_createdConnectionUuid) { 0272 QObject *rootItem = m_ui->connectionView->rootObject(); 0273 loadConnectionSettings(connectionSettings); 0274 QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, connectionSettings->id()), Q_ARG(QVariant, newConnection->path())); 0275 m_createdConnectionUuid.clear(); 0276 } 0277 } 0278 } 0279 0280 void KCMNetworkmanagement::onRequestCreateConnection(int connectionType, const QString &vpnType, const QString &specificType, bool shared) 0281 { 0282 auto type = static_cast<NetworkManager::ConnectionSettings::ConnectionType>(connectionType); 0283 0284 if (type == NetworkManager::ConnectionSettings::Vpn && vpnType == "imported") { 0285 ImportResult result = importVpn(); 0286 0287 if (!result.success) { 0288 m_errorWidget->setText(i18n("Failed to import VPN connection: %1", result.errorMessage)); 0289 m_errorWidget->setVisible(true); 0290 } else { 0291 m_errorWidget->setVisible(false); 0292 } 0293 0294 } else if (type == NetworkManager::ConnectionSettings::Gsm) { // launch the mobile broadband wizard, both gsm/cdma 0295 QPointer<MobileConnectionWizard> wizard = new MobileConnectionWizard(NetworkManager::ConnectionSettings::Unknown, this); 0296 wizard->setAttribute(Qt::WA_DeleteOnClose); 0297 connect(wizard.data(), &MobileConnectionWizard::accepted, [wizard, this]() { 0298 if (wizard->getError() == MobileProviders::Success) { 0299 qCDebug(PLASMA_NM_KCM_LOG) << "Mobile broadband wizard finished:" << wizard->type() << wizard->args(); 0300 0301 if (wizard->args().count() == 2) { 0302 auto tmp = qdbus_cast<QVariantMap>(wizard->args().value(1)); 0303 0304 NetworkManager::ConnectionSettings::Ptr connectionSettings; 0305 connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(wizard->type())); 0306 connectionSettings->setId(wizard->args().value(0).toString()); 0307 if (wizard->type() == NetworkManager::ConnectionSettings::Gsm) { 0308 NetworkManager::GsmSetting::Ptr gsmSetting = 0309 connectionSettings->setting(NetworkManager::Setting::Gsm).staticCast<NetworkManager::GsmSetting>(); 0310 gsmSetting->fromMap(tmp); 0311 gsmSetting->setPasswordFlags(NetworkManager::Setting::NotRequired); 0312 gsmSetting->setPinFlags(NetworkManager::Setting::NotRequired); 0313 } else if (wizard->type() == NetworkManager::ConnectionSettings::Cdma) { 0314 connectionSettings->setting(NetworkManager::Setting::Cdma)->fromMap(tmp); 0315 } else { 0316 qCWarning(PLASMA_NM_KCM_LOG) << Q_FUNC_INFO << "Unhandled setting type"; 0317 } 0318 // Generate new UUID 0319 connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); 0320 addConnection(connectionSettings); 0321 } else { 0322 qCWarning(PLASMA_NM_KCM_LOG) << Q_FUNC_INFO << "Unexpected number of args to parse"; 0323 } 0324 } 0325 }); 0326 wizard->setModal(true); 0327 wizard->show(); 0328 } else { 0329 NetworkManager::ConnectionSettings::Ptr connectionSettings; 0330 connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(type)); 0331 0332 if (type == NetworkManager::ConnectionSettings::Vpn) { 0333 NetworkManager::VpnSetting::Ptr vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast<NetworkManager::VpnSetting>(); 0334 vpnSetting->setServiceType(vpnType); 0335 // Set VPN subtype in case of Openconnect to add support for juniper 0336 if (vpnType == QLatin1String("org.freedesktop.NetworkManager.openconnect")) { 0337 NMStringMap data = vpnSetting->data(); 0338 data.insert(QLatin1String("protocol"), specificType); 0339 vpnSetting->setData(data); 0340 } 0341 } 0342 0343 if (type == NetworkManager::ConnectionSettings::Wired || type == NetworkManager::ConnectionSettings::Wireless) { 0344 // Set auto-negotiate to true, NM sets it to false by default, but we used to have this before and also 0345 // I don't think it's wise to request users to specify speed and duplex as most of them don't know what is that 0346 // and what to set 0347 if (type == NetworkManager::ConnectionSettings::Wired) { 0348 NetworkManager::WiredSetting::Ptr wiredSetting = 0349 connectionSettings->setting(NetworkManager::Setting::Wired).dynamicCast<NetworkManager::WiredSetting>(); 0350 wiredSetting->setAutoNegotiate(true); 0351 } 0352 0353 if (shared) { 0354 if (type == NetworkManager::ConnectionSettings::Wireless) { 0355 NetworkManager::WirelessSetting::Ptr wifiSetting = 0356 connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>(); 0357 wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); 0358 wifiSetting->setSsid(i18n("my_shared_connection").toUtf8()); 0359 0360 for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { 0361 if (device->type() == NetworkManager::Device::Wifi) { 0362 NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast<NetworkManager::WirelessDevice>(); 0363 if (wifiDev) { 0364 if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { 0365 wifiSetting->setMode(NetworkManager::WirelessSetting::Ap); 0366 wifiSetting->setMacAddress(NetworkManager::macAddressFromString(wifiDev->permanentHardwareAddress())); 0367 } 0368 } 0369 } 0370 } 0371 } 0372 0373 NetworkManager::Ipv4Setting::Ptr ipv4Setting = 0374 connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast<NetworkManager::Ipv4Setting>(); 0375 ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Shared); 0376 connectionSettings->setAutoconnect(false); 0377 } 0378 } 0379 if (type == NetworkManager::ConnectionSettings::WireGuard) { 0380 NetworkManager::WireGuardSetting::Ptr wireguardSetting = 0381 connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast<NetworkManager::WireGuardSetting>(); 0382 NetworkManager::Ipv4Setting::Ptr ipv4Setting = 0383 connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast<NetworkManager::Ipv4Setting>(); 0384 NetworkManager::Ipv6Setting::Ptr ipv6Setting = 0385 connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast<NetworkManager::Ipv6Setting>(); 0386 connectionSettings->setAutoconnect(false); 0387 ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Disabled); 0388 ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Ignored); 0389 } 0390 // Generate new UUID 0391 connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); 0392 addConnection(connectionSettings); 0393 } 0394 0395 // Automatically enable virtual connection management if one is created 0396 if (type == NetworkManager::ConnectionSettings::Vlan || type == NetworkManager::ConnectionSettings::Bridge 0397 || type == NetworkManager::ConnectionSettings::Bond || type == NetworkManager::ConnectionSettings::Team) { 0398 Configuration::self().setManageVirtualConnections(true); 0399 } 0400 } 0401 0402 void KCMNetworkmanagement::onRequestExportConnection(const QString &connectionPath) 0403 { 0404 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionPath); 0405 if (!connection) { 0406 return; 0407 } 0408 0409 NetworkManager::ConnectionSettings::Ptr connSettings = connection->settings(); 0410 0411 if (connSettings->connectionType() != NetworkManager::ConnectionSettings::Vpn) 0412 return; 0413 0414 NetworkManager::VpnSetting::Ptr vpnSetting = connSettings->setting(NetworkManager::Setting::Vpn).dynamicCast<NetworkManager::VpnSetting>(); 0415 0416 qCDebug(PLASMA_NM_KCM_LOG) << "Exporting VPN connection" << connection->name() << "type:" << vpnSetting->serviceType(); 0417 0418 const auto result = VpnUiPlugin::loadPluginForType(nullptr, vpnSetting->serviceType()); 0419 0420 if (result) { 0421 std::unique_ptr<VpnUiPlugin> vpnPlugin(result.plugin); 0422 if (vpnPlugin->suggestedFileName(connSettings).isEmpty()) { // this VPN doesn't support export 0423 qCWarning(PLASMA_NM_KCM_LOG) << "This VPN doesn't support export"; 0424 return; 0425 } 0426 0427 const QString url = 0428 QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + vpnPlugin->suggestedFileName(connSettings); 0429 const QString filename = 0430 QFileDialog::getSaveFileName(this, i18n("Export VPN Connection"), url, vpnPlugin->supportedFileExtensions().join(QLatin1Char(' '))); 0431 if (!filename.isEmpty()) { 0432 if (auto result = vpnPlugin->exportConnectionSettings(connSettings, filename)) { 0433 // TODO display success 0434 } else { 0435 // TODO display failure 0436 qCWarning(PLASMA_NM_KCM_LOG) << "Failed to export VPN connection" << result.errorMessage(); 0437 } 0438 } 0439 } else { 0440 qCWarning(PLASMA_NM_KCM_LOG) << "Error getting VpnUiPlugin for export:" << result.errorText; 0441 } 0442 } 0443 0444 void KCMNetworkmanagement::onRequestToChangeConnection(const QString &connectionName, const QString &connectionPath) 0445 { 0446 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); 0447 0448 if (connection) { 0449 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0450 if (KMessageBox::questionTwoActions(this, 0451 #else 0452 if (KMessageBox::questionYesNo(this, 0453 0454 #endif 0455 i18n("Do you want to save changes made to the connection '%1'?", connection->name()), 0456 i18nc("@title:window", "Save Changes"), 0457 KStandardGuiItem::save(), 0458 KStandardGuiItem::discard(), 0459 QString(), 0460 KMessageBox::Notify) 0461 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0462 == KMessageBox::ButtonCode::PrimaryAction) { 0463 #else 0464 == KMessageBox::Yes) { 0465 #endif 0466 save(); 0467 } 0468 } 0469 0470 QObject *rootItem = m_ui->connectionView->rootObject(); 0471 QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, connectionName), Q_ARG(QVariant, connectionPath)); 0472 } 0473 0474 void KCMNetworkmanagement::onSelectedConnectionChanged(const QString &connectionPath) 0475 { 0476 if (connectionPath.isEmpty()) { 0477 resetSelection(); 0478 return; 0479 } 0480 0481 m_currentConnectionPath = connectionPath; 0482 0483 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); 0484 if (connection) { 0485 NetworkManager::ConnectionSettings::Ptr connectionSettings = connection->settings(); 0486 loadConnectionSettings(connectionSettings); 0487 } 0488 } 0489 0490 void KCMNetworkmanagement::addConnection(const NetworkManager::ConnectionSettings::Ptr &connectionSettings) 0491 { 0492 QPointer<ConnectionEditorDialog> editor = new ConnectionEditorDialog(connectionSettings); 0493 editor->setAttribute(Qt::WA_DeleteOnClose); 0494 connect(editor.data(), &ConnectionEditorDialog::accepted, [connectionSettings, editor, this]() { 0495 // We got confirmation so watch this connection and select it once it is created 0496 m_createdConnectionUuid = connectionSettings->uuid(); 0497 m_handler->addConnection(editor->setting()); 0498 }); 0499 editor->setModal(true); 0500 editor->show(); 0501 } 0502 0503 void KCMNetworkmanagement::kcmChanged(bool kcmChanged) 0504 { 0505 m_ui->connectionView->rootContext()->setContextProperty("connectionModified", kcmChanged); 0506 Q_EMIT changed(kcmChanged); 0507 } 0508 0509 void KCMNetworkmanagement::loadConnectionSettings(const NetworkManager::ConnectionSettings::Ptr &connectionSettings) 0510 { 0511 if (m_tabWidget) { 0512 m_tabWidget->setConnection(connectionSettings); 0513 } else { 0514 m_tabWidget = new ConnectionEditorTabWidget(connectionSettings); 0515 connect(m_tabWidget, &ConnectionEditorTabWidget::settingChanged, [this]() { 0516 if (m_tabWidget->isInitialized() && m_tabWidget->isValid()) { 0517 kcmChanged(true); 0518 } 0519 }); 0520 connect(m_tabWidget, &ConnectionEditorTabWidget::validityChanged, [this](bool valid) { 0521 if (m_tabWidget->isInitialized() && m_tabWidget->isValid() != valid) { 0522 kcmChanged(valid); 0523 } 0524 }); 0525 m_ui->horizontalLayout->addWidget(m_tabWidget); 0526 } 0527 0528 kcmChanged(false); 0529 } 0530 0531 KCMNetworkmanagement::ImportResult KCMNetworkmanagement::ImportResult::pass() 0532 { 0533 return {true, QString()}; 0534 } 0535 0536 KCMNetworkmanagement::ImportResult KCMNetworkmanagement::ImportResult::fail(const QString &message) 0537 { 0538 return {false, message}; 0539 } 0540 0541 KCMNetworkmanagement::ImportResult KCMNetworkmanagement::importVpn() 0542 { 0543 // get the list of supported extensions 0544 const QVector<KPluginMetaData> services = KPluginMetaData::findPlugins(QStringLiteral("plasma/network/vpn")); 0545 QStringList extensions; 0546 for (const KPluginMetaData &service : services) { 0547 const auto result = KPluginFactory::instantiatePlugin<VpnUiPlugin>(service); 0548 if (result) { 0549 extensions += result.plugin->supportedFileExtensions(); 0550 delete result.plugin; 0551 } 0552 } 0553 0554 const QString &filename = 0555 QFileDialog::getOpenFileName(this, i18n("Import VPN Connection"), QDir::homePath(), i18n("VPN connections (%1)", extensions.join(QLatin1Char(' ')))); 0556 0557 if (filename.isEmpty()) { 0558 return ImportResult::fail(i18n("No file was provided")); 0559 } 0560 0561 QFileInfo fi(filename); 0562 const QString ext = QStringLiteral("*.") % fi.suffix(); 0563 qCDebug(PLASMA_NM_KCM_LOG) << "Importing VPN connection " << filename << "extension:" << ext; 0564 0565 // Handle WireGuard separately because it is different than all the other VPNs 0566 if (WireGuardInterfaceWidget::supportedFileExtensions().contains(ext)) { 0567 #if NM_CHECK_VERSION(1, 40, 0) 0568 GError *error = nullptr; 0569 NMConnection *conn = nm_conn_wireguard_import(filename.toUtf8().constData(), &error); 0570 0571 if (error) { 0572 qCDebug(PLASMA_NM_KCM_LOG) << "Could not import WireGuard connection" << error->message; 0573 } else { 0574 m_handler->addConnection(conn); 0575 return ImportResult::pass(); 0576 } 0577 #else 0578 NMVariantMapMap connection = WireGuardInterfaceWidget::importConnectionSettings(filename); 0579 NetworkManager::ConnectionSettings connectionSettings; 0580 connectionSettings.fromMap(connection); 0581 connectionSettings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); 0582 0583 // qCDebug(PLASMA_NM_KCM_LOG) << "Converted connection:" << connectionSettings; 0584 0585 m_handler->addConnection(connectionSettings.toMap()); 0586 // qCDebug(PLASMA_NM_KCM_LOG) << "Adding imported connection under id:" << conId; 0587 0588 if (!connection.isEmpty()) { 0589 return ImportResult::pass(); // get out if the import produced at least some output 0590 } 0591 #endif 0592 } 0593 for (const KPluginMetaData &service : services) { 0594 const auto result = KPluginFactory::instantiatePlugin<VpnUiPlugin>(service); 0595 0596 if (!result) { 0597 continue; 0598 } 0599 0600 std::unique_ptr<VpnUiPlugin> vpnPlugin(result.plugin); 0601 0602 if (vpnPlugin->supportedFileExtensions().contains(ext)) { 0603 qCDebug(PLASMA_NM_KCM_LOG) << "Found VPN plugin" << service.name() << ", type:" << service.value("X-NetworkManager-Services"); 0604 0605 VpnUiPlugin::ImportResult result = vpnPlugin->importConnectionSettings(filename); 0606 0607 if (!result) { 0608 qWarning(PLASMA_NM_KCM_LOG) << "Failed to import" << filename << result.errorMessage(); 0609 return ImportResult::fail(result.errorMessage()); 0610 } 0611 0612 m_handler->addConnection(result.connection()); 0613 0614 // qCDebug(PLASMA_NM_KCM_LOG) << "Adding imported connection under id:" << conId; 0615 return ImportResult::pass(); 0616 } 0617 } 0618 0619 return ImportResult::fail(i18n("Unknown VPN type")); 0620 } 0621 0622 void KCMNetworkmanagement::resetSelection() 0623 { 0624 // Reset selected connections 0625 m_currentConnectionPath.clear(); 0626 QObject *rootItem = m_ui->connectionView->rootObject(); 0627 QMetaObject::invokeMethod(rootItem, "deselectConnections"); 0628 if (m_tabWidget) { 0629 delete m_tabWidget; 0630 m_tabWidget = nullptr; 0631 } 0632 Q_EMIT changed(false); 0633 } 0634 0635 #include "kcm.moc"