File indexing completed on 2024-05-05 17:32:29

0001 // SPDX-FileCopyrightText: 2021 Nicolas Fella <nicolas.fella@gmx.de>
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "modemcontroller.h"
0006 
0007 #include <ModemManagerQt/Manager>
0008 
0009 ModemController &ModemController::instance()
0010 {
0011     static ModemController instance;
0012     return instance;
0013 }
0014 
0015 ModemController::ModemController()
0016     : QObject()
0017 {
0018     connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, [this](const QString &udi) {
0019         init(udi);
0020     });
0021 }
0022 
0023 std::optional<QDBusPendingReply<QDBusObjectPath>> ModemController::createMessage(ModemManager::ModemMessaging::Message m)
0024 {
0025     if (!m_msgManager) {
0026         return {};
0027     }
0028 
0029     return m_msgManager->createMessage(m);
0030 }
0031 
0032 void ModemController::init(std::optional<QString> modemPath)
0033 {
0034     if (modemPath) {
0035         m_modem = ModemManager::findModemDevice(*modemPath);
0036     } else {
0037         ModemManager::ModemDevice::List devices = ModemManager::modemDevices();
0038         if (!devices.isEmpty()) {
0039             m_modem = devices.first();
0040         }
0041     }
0042 
0043     if (!m_modem) {
0044         qWarning() << "Could not find modem" << modemPath.value_or(QString());
0045         return;
0046     }
0047 
0048     if (m_modem->hasInterface(ModemManager::ModemDevice::GsmInterface)) {
0049         m_modem3gpp = m_modem->interface(ModemManager::ModemDevice::GsmInterface).objectCast<ModemManager::Modem3gpp>();
0050         countryCode = m_modem3gpp->countryCode();
0051         qDebug() << "Country Code:" << countryCode;
0052 
0053         connect(m_modem3gpp.get(), &ModemManager::Modem3gpp::countryCodeChanged, this, [this](const QString &code) {
0054             countryCode = code;
0055             Q_EMIT countryCodeChanged(code);
0056             qDebug() << "country code changed" << code;
0057         });
0058 
0059         if (countryCode.isEmpty()) {
0060             qWarning() << "Country code is null! Phone numbers may not be interpreted correctly";
0061         }
0062     }
0063 
0064     m_interface = m_modem->modemInterface();
0065 
0066     connect(m_interface.get(), &ModemManager::Modem::bearerAdded, this, [this](const QString &bearer) {
0067         m_bearer = m_interface->findBearer(bearer);
0068 
0069         QList<QSharedPointer<ModemManager::Bearer>> bearers = m_interface->listBearers();
0070         for (const ModemManager::Bearer::Ptr &item : bearers) {
0071             if (item->uni() != bearer) {
0072                 item->disconnect();
0073                 m_interface->deleteBearer(item->uni());
0074             }
0075         }
0076 
0077         // whether or not the bearer is connected and thus whether packet data communication using this bearer is possible
0078         connect(m_bearer.data(), &ModemManager::Bearer::connectedChanged, this, [this](bool isConnected) {
0079             Q_EMIT modemDataConnectedChanged(isConnected);
0080             qDebug() << "bearer connected:" << isConnected;
0081         });
0082 
0083         // In some devices, packet data service will be suspended while the device is handling other communication, like a voice call
0084         connect(m_bearer.data(), &ModemManager::Bearer::suspendedChanged, this, [this](bool isSuspended) {
0085             Q_EMIT modemDataConnectedChanged(!isSuspended);
0086             qDebug() << "bearer suspended:" << isSuspended;
0087         });
0088 
0089         dnsServers = getDNS(m_bearer);
0090         qDebug() << "dns:" << dnsServers;
0091         connect(m_bearer.data(), &ModemManager::Bearer::ip4ConfigChanged, this, [this, bearers](const ModemManager::IpConfig &ipv4Config) {
0092             dnsServers = getDNS(m_bearer);
0093             qDebug() << "dns4 updated:" << dnsServers;
0094         });
0095 
0096         connect(m_bearer.data(), &ModemManager::Bearer::ip6ConfigChanged, this, [this, bearers](const ModemManager::IpConfig &ipv6Config) {
0097             dnsServers = getDNS(m_bearer);
0098             qDebug() << "dns6 updated:" << dnsServers;
0099         });
0100 
0101         ifaceName = m_bearer->interface();
0102         qDebug() << "interface:" << ifaceName;
0103         connect(m_bearer.data(), &ModemManager::Bearer::interfaceChanged, this, [this](const QString &iface) {
0104             ifaceName = iface;
0105             qDebug() << "interface changed:" << ifaceName;
0106         });
0107     });
0108 
0109     connect(m_modem.get(), &ModemManager::ModemDevice::interfaceAdded, this, [this](ModemManager::ModemDevice::InterfaceType type) {
0110         if (type == ModemManager::ModemDevice::MessagingInterface) {
0111             initMessaging();
0112         }
0113     });
0114 
0115     if (m_modem->hasInterface(ModemManager::ModemDevice::MessagingInterface)) {
0116         initMessaging();
0117     }
0118 
0119     connect(m_interface.get(), &ModemManager::Modem::stateChanged, this, [this](MMModemState oldState, MMModemState newState, MMModemStateChangeReason reason) {
0120         Q_UNUSED(oldState);
0121         Q_UNUSED(reason);
0122         if (newState == MMModemState::MM_MODEM_STATE_CONNECTED) {
0123             Q_EMIT modemConnected();
0124             Q_EMIT modemDataConnectedChanged(m_bearer ? m_bearer->isConnected() : false);
0125         }
0126     });
0127 }
0128 
0129 void ModemController::initMessaging()
0130 {
0131     Q_ASSERT(m_modem);
0132     Q_ASSERT(m_modem->hasInterface(ModemManager::ModemDevice::MessagingInterface));
0133 
0134     m_msgManager = m_modem->messagingInterface();
0135 
0136     connect(m_msgManager.get(), &ModemManager::ModemMessaging::messageAdded, this, &ModemController::slotMessageAdded, Qt::UniqueConnection);
0137 
0138     Q_EMIT modemConnected();
0139 }
0140 
0141 void ModemController::slotMessageAdded(const QString &uni, bool received)
0142 {
0143     // true if the message was received from the network, as opposed to being added locally
0144     if (!received) {
0145         return;
0146     }
0147 
0148     ModemManager::Sms::Ptr msg = m_msgManager->findMessage(uni);
0149     Q_ASSERT(msg);
0150 
0151     if (msg->state() == MMSmsState::MM_SMS_STATE_RECEIVING) {
0152         connect(msg.get(), &ModemManager::Sms::dataChanged, this, [this, msg]() {
0153             if (msg->state() == MMSmsState::MM_SMS_STATE_RECEIVED) {
0154                 if (!msg->data().isEmpty()) {
0155                     Q_EMIT messageAdded(msg);
0156                 }
0157             }
0158         });
0159         connect(msg.get(), &ModemManager::Sms::textChanged, this, [this, msg]() {
0160             if (msg->state() == MMSmsState::MM_SMS_STATE_RECEIVED) {
0161                 if (!msg->text().isEmpty()) {
0162                     Q_EMIT messageAdded(msg);
0163                 }
0164             }
0165         });
0166     } else {
0167         Q_EMIT messageAdded(msg);
0168     }
0169 }
0170 
0171 void ModemController::deleteMessage(const QString &uni)
0172 {
0173     if (!m_msgManager) {
0174         return;
0175     }
0176 
0177     m_msgManager->deleteMessage(uni);
0178 }
0179 
0180 ModemManager::Sms::List ModemController::messages()
0181 {
0182     if (!m_msgManager) {
0183         ModemManager::Sms::List list;
0184         return list;
0185     }
0186 
0187     return m_msgManager->messages();
0188 }
0189 
0190 QString ModemController::ownNumber()
0191 {
0192     if (!m_interface) {
0193         return QString();
0194     }
0195 
0196     const QStringList numbers = m_interface->ownNumbers();
0197 
0198     if (!numbers.isEmpty()) {
0199         if (numbers.startsWith(QStringLiteral("+"))) {
0200             return numbers.first();
0201         }
0202         return QStringLiteral("+") + numbers.first();
0203     }
0204 
0205     return QString();
0206 }
0207 
0208 QString ModemController::getDNS(QSharedPointer<ModemManager::Bearer> bearer)
0209 {
0210     QStringList dnsServerList = {bearer->ip4Config().dns1(),
0211                                  bearer->ip4Config().dns2(),
0212                                  bearer->ip4Config().dns3(),
0213                                  bearer->ip6Config().dns1(),
0214                                  bearer->ip6Config().dns2(),
0215                                  bearer->ip6Config().dns3()};
0216 
0217     // remove empty items
0218     dnsServerList.removeAll(QString());
0219 
0220     return dnsServerList.join(QStringLiteral(","));
0221 }