File indexing completed on 2024-04-28 05:33:52

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