File indexing completed on 2024-04-14 15:39:56

0001 /*
0002     SPDX-FileCopyrightText: 2009 Will Stephenson <wstephenson@kde.org>
0003     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0004     SPDX-FileCopyrightText: 2014 Jan Grulich <jgrulich@redhat.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "modemmonitor.h"
0010 #include "plasma_nm_kded.h"
0011 
0012 #include <QDBusPendingReply>
0013 
0014 #include <KConfigGroup>
0015 #include <KLocalizedString>
0016 #include <KMessageBox>
0017 #include <KSharedConfig>
0018 
0019 #include <NetworkManagerQt/Connection>
0020 #include <NetworkManagerQt/Device>
0021 #include <NetworkManagerQt/GsmSetting>
0022 #include <NetworkManagerQt/Manager>
0023 
0024 #include <ModemManager/ModemManager.h>
0025 #include <ModemManagerQt/Manager>
0026 #include <ModemManagerQt/Sim>
0027 
0028 #include "pindialog.h"
0029 
0030 class ModemMonitorPrivate
0031 {
0032 public:
0033     QPointer<PinDialog> dialog;
0034 };
0035 
0036 ModemMonitor::ModemMonitor(QObject *parent)
0037     : QObject(parent)
0038     , d_ptr(new ModemMonitorPrivate)
0039 {
0040     Q_D(ModemMonitor);
0041     d->dialog.clear();
0042 
0043     KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("plasma-nm"));
0044     KConfigGroup grp(config, QLatin1String("General"));
0045 
0046     if (grp.isValid()) {
0047         if (grp.readEntry(QLatin1String("UnlockModemOnDetection"), true)) {
0048             connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, &ModemMonitor::unlockModem);
0049             for (const ModemManager::ModemDevice::Ptr &iface : ModemManager::modemDevices()) {
0050                 unlockModem(iface->uni());
0051             }
0052         }
0053     }
0054 }
0055 
0056 ModemMonitor::~ModemMonitor()
0057 {
0058     delete d_ptr;
0059 }
0060 
0061 void ModemMonitor::unlockModem(const QString &modemUni)
0062 {
0063     Q_D(ModemMonitor);
0064 
0065     ModemManager::Modem::Ptr modem;
0066     ModemManager::ModemDevice::Ptr modemDevice = ModemManager::findModemDevice(modemUni);
0067     if (modemDevice) {
0068         modem = modemDevice->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
0069     } else {
0070         return;
0071     }
0072 
0073     connect(modem.data(), &ModemManager::Modem::unlockRequiredChanged, this, &ModemMonitor::requestPin, Qt::UniqueConnection);
0074 
0075     if (d->dialog || (modem && modem->unlockRequired() == MM_MODEM_LOCK_NONE) || (modem && modem->unlockRequired() == MM_MODEM_LOCK_UNKNOWN)) {
0076         return;
0077     }
0078 
0079     if (modem) {
0080         // Using queued invocation to prevent kded stalling here until user enters the pin.
0081         QMetaObject::invokeMethod(modem.data(), "unlockRequiredChanged", Qt::QueuedConnection, Q_ARG(MMModemLock, modem->unlockRequired()));
0082     }
0083 }
0084 
0085 void ModemMonitor::requestPin(MMModemLock lock)
0086 {
0087     Q_D(ModemMonitor);
0088     qCDebug(PLASMA_NM_KDED_LOG) << "unlockRequired == " << lock;
0089     // Handle just SIM-PIN and SIM-PUK, because some other types may cause problems and they are not also handled by nm-applet
0090     if (lock == MM_MODEM_LOCK_NONE || lock == MM_MODEM_LOCK_UNKNOWN || (lock != MM_MODEM_LOCK_SIM_PIN && lock != MM_MODEM_LOCK_SIM_PUK)) {
0091         return;
0092     }
0093 
0094     auto modem = qobject_cast<ModemManager::Modem *>(sender());
0095     if (!modem) {
0096         return;
0097     }
0098 
0099     if (d->dialog) {
0100         qCDebug(PLASMA_NM_KDED_LOG) << "PinDialog already running";
0101         return;
0102     }
0103 
0104 #define MM_DIALOG(lockType, dialogType)                                                                                                                        \
0105     if (lock == lockType) {                                                                                                                                    \
0106         d->dialog = QPointer<PinDialog>(new PinDialog(modem, PinDialog::dialogType));                                                                          \
0107     }
0108 
0109     // clang-format off
0110     /**/ MM_DIALOG(MM_MODEM_LOCK_SIM_PIN, SimPin)
0111     else MM_DIALOG(MM_MODEM_LOCK_SIM_PIN2, SimPin2)
0112     else MM_DIALOG(MM_MODEM_LOCK_SIM_PUK, SimPuk)
0113     else MM_DIALOG(MM_MODEM_LOCK_SIM_PUK2, SimPuk2)
0114     else MM_DIALOG(MM_MODEM_LOCK_PH_SP_PIN, ModemServiceProviderPin)
0115     else MM_DIALOG(MM_MODEM_LOCK_PH_SP_PUK, ModemServiceProviderPuk)
0116     else MM_DIALOG(MM_MODEM_LOCK_PH_NET_PIN, ModemNetworkPin)
0117     else MM_DIALOG(MM_MODEM_LOCK_PH_NET_PUK, ModemNetworkPuk)
0118     else MM_DIALOG(MM_MODEM_LOCK_PH_SIM_PIN, ModemPin)
0119     else MM_DIALOG(MM_MODEM_LOCK_PH_CORP_PIN, ModemCorporatePin)
0120     else MM_DIALOG(MM_MODEM_LOCK_PH_CORP_PUK, ModemCorporatePuk)
0121     else MM_DIALOG(MM_MODEM_LOCK_PH_FSIM_PIN, ModemPhFsimPin)
0122     else MM_DIALOG(MM_MODEM_LOCK_PH_FSIM_PUK, ModemPhFsimPuk)
0123     else MM_DIALOG(MM_MODEM_LOCK_PH_NETSUB_PIN, ModemNetworkSubsetPin)
0124     else MM_DIALOG(MM_MODEM_LOCK_PH_NETSUB_PUK, ModemNetworkSubsetPuk);
0125     // clang-format on
0126 
0127     if (d->dialog.data()->exec() != QDialog::Accepted) {
0128         goto OUT;
0129     }
0130 
0131     qCDebug(PLASMA_NM_KDED_LOG) << "Sending unlock code";
0132 
0133     {
0134         ModemManager::Sim::Ptr sim;
0135         ModemManager::ModemDevice::Ptr modemDevice = ModemManager::findModemDevice(modem->uni());
0136         if (modemDevice && modemDevice->sim()) {
0137             sim = modemDevice->sim();
0138         }
0139 
0140         if (!sim) {
0141             return;
0142         }
0143 
0144         QDBusPendingCallWatcher *watcher = nullptr;
0145 
0146         PinDialog::Type type = d->dialog.data()->type();
0147 
0148         if (type == PinDialog::SimPin || type == PinDialog::SimPin2 //
0149             || type == PinDialog::ModemServiceProviderPin || type == PinDialog::ModemNetworkPin //
0150             || type == PinDialog::ModemPin || type == PinDialog::ModemCorporatePin //
0151             || type == PinDialog::ModemPhFsimPin || type == PinDialog::ModemNetworkSubsetPin) {
0152             QDBusPendingCall reply = sim->sendPin(d->dialog.data()->pin());
0153             watcher = new QDBusPendingCallWatcher(reply, sim.data());
0154         } else if (type == PinDialog::SimPuk //
0155                    || type == PinDialog::SimPuk2 || type == PinDialog::ModemServiceProviderPuk //
0156                    || type == PinDialog::ModemNetworkPuk || type == PinDialog::ModemCorporatePuk //
0157                    || type == PinDialog::ModemPhFsimPuk || type == PinDialog::ModemNetworkSubsetPuk) {
0158             QDBusPendingCall reply = sim->sendPuk(d->dialog.data()->puk(), d->dialog.data()->pin());
0159             watcher = new QDBusPendingCallWatcher(reply, sim.data());
0160         }
0161 
0162         connect(watcher, &QDBusPendingCallWatcher::finished, this, &ModemMonitor::onSendPinArrived);
0163     }
0164 
0165 OUT:
0166     if (d->dialog) {
0167         d->dialog.data()->deleteLater();
0168     }
0169     d->dialog.clear();
0170 }
0171 
0172 void ModemMonitor::onSendPinArrived(QDBusPendingCallWatcher *watcher)
0173 {
0174     QDBusPendingReply<> reply = *watcher;
0175 
0176     if (reply.isValid()) {
0177         // Automatically enabling this for cell phones with expensive data plans is not a good idea.
0178         // NetworkManager::setWwanEnabled(true);
0179     } else {
0180         KMessageBox::error(nullptr,
0181                            i18nc("Text in GSM PIN/PUK unlock error dialog", "Error unlocking modem: %1", reply.error().message()),
0182                            i18nc("Title for GSM PIN/PUK unlock error dialog", "PIN/PUK unlock error"));
0183     }
0184 
0185     watcher->deleteLater();
0186 }