2021-07-30 14:19:46 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
2023-02-23 16:43:38 +00:00
|
|
|
// SPDX-FileCopyrightText: 2022-2023 Devin Lin <devin@kde.org>
|
2021-07-30 14:19:46 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
2023-02-23 16:43:38 +00:00
|
|
|
#include "signalindicator.h"
|
|
|
|
|
|
2022-02-13 04:07:09 +00:00
|
|
|
#include <NetworkManagerQt/GsmSetting>
|
2022-02-11 03:50:09 +00:00
|
|
|
#include <NetworkManagerQt/Manager>
|
2022-10-23 16:12:40 +00:00
|
|
|
#include <NetworkManagerQt/Settings>
|
|
|
|
|
#include <NetworkManagerQt/Utils>
|
2022-02-11 03:50:09 +00:00
|
|
|
|
2023-02-23 16:43:38 +00:00
|
|
|
#include <KUser>
|
2021-07-30 14:19:46 +00:00
|
|
|
|
2023-04-01 07:09:57 +00:00
|
|
|
#include "signalindicator.h"
|
|
|
|
|
|
2022-10-23 17:45:29 +00:00
|
|
|
SignalIndicator::SignalIndicator(QObject *parent)
|
|
|
|
|
: QObject{parent}
|
|
|
|
|
, m_nmModem{nullptr}
|
|
|
|
|
, m_modemDevice{nullptr}
|
|
|
|
|
, m_modem{nullptr}
|
|
|
|
|
, m_3gppModem{nullptr}
|
2021-07-30 14:19:46 +00:00
|
|
|
{
|
2022-10-23 16:12:40 +00:00
|
|
|
connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, &SignalIndicator::updateModemManagerModem);
|
|
|
|
|
connect(ModemManager::notifier(), &ModemManager::Notifier::modemRemoved, this, &SignalIndicator::updateModemManagerModem);
|
|
|
|
|
|
2022-10-23 19:33:47 +00:00
|
|
|
connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &SignalIndicator::mobileDataEnabledChanged);
|
|
|
|
|
connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, &SignalIndicator::mobileDataEnabledChanged);
|
|
|
|
|
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &SignalIndicator::mobileDataEnabledChanged);
|
|
|
|
|
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &SignalIndicator::mobileDataEnabledChanged);
|
2022-10-23 16:12:40 +00:00
|
|
|
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &SignalIndicator::updateNetworkManagerModem);
|
|
|
|
|
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &SignalIndicator::updateNetworkManagerModem);
|
|
|
|
|
|
|
|
|
|
updateModemManagerModem();
|
2021-07-30 14:19:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SignalIndicator::strength() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_modem) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return m_modem->signalQuality().signal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SignalIndicator::name() const
|
|
|
|
|
{
|
|
|
|
|
return m_3gppModem ? m_3gppModem->operatorName() : QString();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 16:12:40 +00:00
|
|
|
bool SignalIndicator::modemAvailable() const
|
|
|
|
|
{
|
2022-10-23 17:45:29 +00:00
|
|
|
return !m_modem.isNull();
|
2022-10-23 16:12:40 +00:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 14:19:46 +00:00
|
|
|
bool SignalIndicator::simLocked() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_modem) {
|
2021-12-05 22:39:08 +00:00
|
|
|
return false;
|
2021-07-30 14:19:46 +00:00
|
|
|
}
|
2022-02-11 03:13:25 +00:00
|
|
|
return m_modem->unlockRequired() == MM_MODEM_LOCK_SIM_PIN;
|
2021-07-30 14:19:46 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-12 20:36:19 +00:00
|
|
|
bool SignalIndicator::simEmpty() const
|
|
|
|
|
{
|
2022-10-23 19:16:46 +00:00
|
|
|
return !m_modemDevice || !m_modemDevice->sim() || (m_modemDevice->sim()->uni() == QStringLiteral("/"));
|
2022-09-12 20:36:19 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-13 04:07:09 +00:00
|
|
|
bool SignalIndicator::mobileDataSupported() const
|
2022-02-11 03:50:09 +00:00
|
|
|
{
|
2022-10-23 16:12:40 +00:00
|
|
|
return m_nmModem && !simEmpty();
|
2022-02-11 03:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-13 04:07:09 +00:00
|
|
|
bool SignalIndicator::mobileDataEnabled() const
|
2022-02-11 03:50:09 +00:00
|
|
|
{
|
2022-03-14 17:47:23 +00:00
|
|
|
// no modem -> no mobile data -> report disabled
|
2022-02-13 04:07:09 +00:00
|
|
|
if (!m_nmModem) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-14 17:47:23 +00:00
|
|
|
// mobile data already activated -> report enabled
|
|
|
|
|
if (m_nmModem->state() == NetworkManager::Device::Activated) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// autoconnect disabled on the entire modem -> report disabled
|
|
|
|
|
if (!m_nmModem->autoconnect()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// at least one connection set to autoconnect -> report enabled
|
|
|
|
|
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
|
|
|
|
|
if (con->settings()->autoconnect()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// modem, but no connection, set to autoconnect -> report disabled (#182)
|
|
|
|
|
return false;
|
2022-02-13 04:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-10 03:37:15 +00:00
|
|
|
bool SignalIndicator::needsAPNAdded() const
|
|
|
|
|
{
|
2022-09-11 21:43:54 +00:00
|
|
|
return m_nmModem && mobileDataSupported() && m_nmModem->availableConnections().count() == 0;
|
2022-09-10 03:37:15 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-13 04:07:09 +00:00
|
|
|
void SignalIndicator::setMobileDataEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
if (!m_nmModem) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!enabled) {
|
|
|
|
|
m_nmModem->setAutoconnect(false);
|
2022-03-14 17:47:23 +00:00
|
|
|
// we need to also set all connections to not autoconnect (#182)
|
2022-02-13 04:07:09 +00:00
|
|
|
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
|
2022-03-14 17:47:23 +00:00
|
|
|
con->settings()->setAutoconnect(false);
|
|
|
|
|
con->update(con->settings()->toMap());
|
2022-02-13 04:07:09 +00:00
|
|
|
}
|
2022-10-23 16:12:40 +00:00
|
|
|
m_nmModem->disconnectInterface();
|
2022-02-13 04:07:09 +00:00
|
|
|
} else {
|
|
|
|
|
m_nmModem->setAutoconnect(true);
|
2022-03-14 17:47:23 +00:00
|
|
|
// activate the connection that was last used
|
|
|
|
|
QDateTime latestTimestamp;
|
|
|
|
|
NetworkManager::Connection::Ptr latestCon;
|
2022-02-13 04:07:09 +00:00
|
|
|
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
|
2022-03-14 17:47:23 +00:00
|
|
|
QDateTime timestamp = con->settings()->timestamp();
|
|
|
|
|
// if con was not used yet, skip it, otherwise:
|
|
|
|
|
// if we have no latestTimestamp yet, con is the latest
|
|
|
|
|
// otherwise, compare the timestamps
|
|
|
|
|
// in case of a tie, use the first connection that was found
|
|
|
|
|
if (!timestamp.isNull() && (latestTimestamp.isNull() || timestamp > latestTimestamp)) {
|
|
|
|
|
latestTimestamp = timestamp;
|
|
|
|
|
latestCon = con;
|
2022-02-13 04:07:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-03-14 17:47:23 +00:00
|
|
|
// if we found the last used connection
|
|
|
|
|
if (!latestCon.isNull()) {
|
|
|
|
|
// set it to autoconnect and connect it immediately
|
|
|
|
|
latestCon->settings()->setAutoconnect(true);
|
|
|
|
|
latestCon->update(latestCon->settings()->toMap());
|
|
|
|
|
NetworkManager::activateConnection(latestCon->path(), m_nmModem->uni(), "");
|
|
|
|
|
}
|
2022-02-13 04:07:09 +00:00
|
|
|
}
|
2022-02-11 03:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 07:09:57 +00:00
|
|
|
QString SignalIndicator::activeConnectionUni() const
|
|
|
|
|
{
|
|
|
|
|
if (m_nmModem && m_nmModem->activeConnection() && m_nmModem->activeConnection()->connection()) {
|
|
|
|
|
return m_nmModem->activeConnection()->connection()->uuid();
|
|
|
|
|
}
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<ProfileSettings *> &SignalIndicator::profileList()
|
|
|
|
|
{
|
|
|
|
|
return m_profileList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalIndicator::refreshProfiles()
|
|
|
|
|
{
|
|
|
|
|
m_profileList.clear();
|
|
|
|
|
|
|
|
|
|
if (!m_nmModem) {
|
|
|
|
|
Q_EMIT profileListChanged();
|
|
|
|
|
qWarning() << "No NetworkManager modem found, cannot refresh profiles.";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto connection : m_nmModem->availableConnections()) {
|
|
|
|
|
for (auto setting : connection->settings()->settings()) {
|
|
|
|
|
if (setting.dynamicCast<NetworkManager::GsmSetting>()) {
|
|
|
|
|
m_profileList.append(new ProfileSettings(this, setting.dynamicCast<NetworkManager::GsmSetting>(), connection));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Q_EMIT profileListChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalIndicator::activateProfile(const QString &connectionUni)
|
|
|
|
|
{
|
|
|
|
|
if (!m_nmModem) {
|
|
|
|
|
qWarning() << "Cannot activate profile since there is no NetworkManager modem";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qDebug() << QStringLiteral("Activating profile on modem") << m_nmModem->uni() << QStringLiteral("for connection") << connectionUni << ".";
|
|
|
|
|
|
|
|
|
|
NetworkManager::Connection::Ptr con;
|
|
|
|
|
|
|
|
|
|
// disable autoconnect for all other connections
|
|
|
|
|
for (auto connection : m_nmModem->availableConnections()) {
|
|
|
|
|
if (connection->uuid() == connectionUni) {
|
|
|
|
|
connection->settings()->setAutoconnect(true);
|
|
|
|
|
con = connection;
|
|
|
|
|
} else {
|
|
|
|
|
connection->settings()->setAutoconnect(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!con) {
|
|
|
|
|
qDebug() << QStringLiteral("Connection") << connectionUni << QStringLiteral("not found.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// activate connection manually
|
|
|
|
|
// despite the documentation saying otherwise, activateConnection seems to need the DBus path, not uuid of the connection
|
|
|
|
|
QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::activateConnection(con->path(), m_nmModem->uni(), {});
|
|
|
|
|
reply.waitForFinished();
|
|
|
|
|
if (reply.isError()) {
|
|
|
|
|
qWarning() << QStringLiteral("Error activating connection:") << reply.error().message();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalIndicator::addProfile(const QString &name, const QString &apn, const QString &username, const QString &password, const QString &networkType)
|
|
|
|
|
{
|
|
|
|
|
if (!m_nmModem) {
|
|
|
|
|
qWarning() << "Cannot add profile since there is no NetworkManager modem";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetworkManager::ConnectionSettings::Ptr settings{new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Gsm)};
|
|
|
|
|
settings->setId(name);
|
|
|
|
|
settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid());
|
|
|
|
|
settings->setAutoconnect(true);
|
|
|
|
|
settings->addToPermissions(KUser().loginName(), QString());
|
|
|
|
|
|
|
|
|
|
NetworkManager::GsmSetting::Ptr gsmSetting = settings->setting(NetworkManager::Setting::Gsm).dynamicCast<NetworkManager::GsmSetting>();
|
|
|
|
|
gsmSetting->setApn(apn);
|
|
|
|
|
gsmSetting->setUsername(username);
|
|
|
|
|
gsmSetting->setPassword(password);
|
|
|
|
|
gsmSetting->setPasswordFlags(password.isEmpty() ? NetworkManager::Setting::NotRequired : NetworkManager::Setting::AgentOwned);
|
|
|
|
|
gsmSetting->setNetworkType(ProfileSettings::networkTypeFlag(networkType));
|
|
|
|
|
|
|
|
|
|
gsmSetting->setInitialized(true);
|
|
|
|
|
|
|
|
|
|
QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addAndActivateConnection(settings->toMap(), m_nmModem->uni(), {});
|
|
|
|
|
reply.waitForFinished();
|
|
|
|
|
if (reply.isError()) {
|
|
|
|
|
qWarning() << "Error adding connection:" << reply.error().message();
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "Successfully added a new connection" << name << "with APN" << apn << ".";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalIndicator::removeProfile(const QString &connectionUni)
|
|
|
|
|
{
|
|
|
|
|
NetworkManager::Connection::Ptr con = NetworkManager::findConnectionByUuid(connectionUni);
|
|
|
|
|
if (!con) {
|
|
|
|
|
qWarning() << "Could not find connection" << connectionUni << "to update!";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDBusPendingReply reply = con->remove();
|
|
|
|
|
reply.waitForFinished();
|
|
|
|
|
if (reply.isError()) {
|
|
|
|
|
qWarning() << "Error removing connection" << reply.error().message();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalIndicator::updateProfile(const QString &connectionUni,
|
|
|
|
|
const QString &name,
|
|
|
|
|
const QString &apn,
|
|
|
|
|
const QString &username,
|
|
|
|
|
const QString &password,
|
|
|
|
|
const QString &networkType)
|
|
|
|
|
{
|
|
|
|
|
NetworkManager::Connection::Ptr con = NetworkManager::findConnectionByUuid(connectionUni);
|
|
|
|
|
if (!con) {
|
|
|
|
|
qWarning() << "Could not find connection" << connectionUni << "to update!";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetworkManager::ConnectionSettings::Ptr conSettings = con->settings();
|
|
|
|
|
if (!conSettings) {
|
|
|
|
|
qWarning() << "Could not find connection settings for" << connectionUni << "to update!";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conSettings->setId(name);
|
|
|
|
|
|
|
|
|
|
NetworkManager::GsmSetting::Ptr gsmSetting = conSettings->setting(NetworkManager::Setting::Gsm).dynamicCast<NetworkManager::GsmSetting>();
|
|
|
|
|
gsmSetting->setApn(apn);
|
|
|
|
|
gsmSetting->setUsername(username);
|
|
|
|
|
gsmSetting->setPassword(password);
|
|
|
|
|
gsmSetting->setPasswordFlags(password.isEmpty() ? NetworkManager::Setting::NotRequired : NetworkManager::Setting::AgentOwned);
|
|
|
|
|
gsmSetting->setNetworkType(ProfileSettings::networkTypeFlag(networkType));
|
|
|
|
|
|
|
|
|
|
gsmSetting->setInitialized(true);
|
|
|
|
|
|
|
|
|
|
QDBusPendingReply reply = con->update(conSettings->toMap());
|
|
|
|
|
reply.waitForFinished();
|
|
|
|
|
if (reply.isError()) {
|
|
|
|
|
qWarning() << "Error updating connection settings for" << connectionUni << ":" << reply.error().message() << ".";
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "Successfully updated connection settings" << connectionUni << ".";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 16:12:40 +00:00
|
|
|
void SignalIndicator::updateModemManagerModem()
|
2021-07-30 14:19:46 +00:00
|
|
|
{
|
2022-10-23 17:45:29 +00:00
|
|
|
m_modemDevice = nullptr;
|
|
|
|
|
m_modem = nullptr;
|
|
|
|
|
m_3gppModem = nullptr;
|
|
|
|
|
|
2022-10-23 16:12:40 +00:00
|
|
|
if (ModemManager::modemDevices().isEmpty()) {
|
2021-07-30 14:19:46 +00:00
|
|
|
qWarning() << "No modems available";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-02-13 04:07:09 +00:00
|
|
|
|
2022-10-23 16:12:40 +00:00
|
|
|
// TODO: we assume that there is a single modem for the time being
|
2022-02-13 04:07:09 +00:00
|
|
|
m_modemDevice = ModemManager::modemDevices()[0];
|
|
|
|
|
m_modem = m_modemDevice->modemInterface();
|
|
|
|
|
m_3gppModem = m_modemDevice->interface(ModemManager::ModemDevice::GsmInterface).objectCast<ModemManager::Modem3gpp>();
|
|
|
|
|
|
2022-10-23 16:12:40 +00:00
|
|
|
connect(m_modemDevice->sim().get(), &ModemManager::Sim::simIdentifierChanged, this, &SignalIndicator::simEmptyChanged);
|
|
|
|
|
|
|
|
|
|
if (m_modem) {
|
|
|
|
|
connect(m_modem.get(), &ModemManager::Modem::signalQualityChanged, this, &SignalIndicator::strengthChanged);
|
|
|
|
|
connect(m_modem.get(), &ModemManager::Modem::unlockRequiredChanged, this, &SignalIndicator::simLockedChanged);
|
|
|
|
|
}
|
|
|
|
|
if (m_3gppModem) {
|
|
|
|
|
connect(m_3gppModem.get(), &ModemManager::Modem3gpp::operatorNameChanged, this, &SignalIndicator::nameChanged);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateNetworkManagerModem();
|
|
|
|
|
|
|
|
|
|
Q_EMIT nameChanged();
|
|
|
|
|
Q_EMIT strengthChanged();
|
|
|
|
|
Q_EMIT modemAvailableChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalIndicator::updateNetworkManagerModem()
|
|
|
|
|
{
|
2022-10-23 17:45:29 +00:00
|
|
|
m_nmModem = nullptr;
|
2022-10-23 16:12:40 +00:00
|
|
|
if (!m_modemDevice) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-13 04:07:09 +00:00
|
|
|
// find networkmanager modem
|
|
|
|
|
for (NetworkManager::Device::Ptr nmDevice : NetworkManager::networkInterfaces()) {
|
|
|
|
|
if (nmDevice->udi() == m_modemDevice->uni()) {
|
|
|
|
|
m_nmModem = nmDevice.objectCast<NetworkManager::ModemDevice>();
|
|
|
|
|
|
2022-10-23 19:33:47 +00:00
|
|
|
connect(m_nmModem.get(), &NetworkManager::Device::autoconnectChanged, this, &SignalIndicator::mobileDataEnabledChanged);
|
|
|
|
|
connect(m_nmModem.get(), &NetworkManager::Device::stateChanged, this, &SignalIndicator::mobileDataEnabledChanged);
|
|
|
|
|
connect(m_nmModem.get(), &NetworkManager::Device::availableConnectionAppeared, this, &SignalIndicator::mobileDataEnabledChanged);
|
|
|
|
|
connect(m_nmModem.get(), &NetworkManager::Device::availableConnectionDisappeared, this, &SignalIndicator::mobileDataEnabledChanged);
|
2023-04-01 07:09:57 +00:00
|
|
|
|
|
|
|
|
connect(m_nmModem.data(), &NetworkManager::ModemDevice::availableConnectionChanged, this, &SignalIndicator::refreshProfiles);
|
|
|
|
|
connect(m_nmModem.data(), &NetworkManager::ModemDevice::activeConnectionChanged, this, [this]() -> void {
|
|
|
|
|
refreshProfiles();
|
|
|
|
|
Q_EMIT activeConnectionUniChanged();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
refreshProfiles();
|
2022-02-13 04:07:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q_EMIT mobileDataSupportedChanged();
|
2022-10-23 16:12:40 +00:00
|
|
|
Q_EMIT mobileDataEnabledChanged();
|
2021-07-30 14:19:46 +00:00
|
|
|
}
|