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