diff --git a/src/appcontext.cpp b/src/appcontext.cpp index e6b36e4..293b11c 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -72,9 +72,9 @@ void AppContext::cachePairedDevices() if (!fileData) { continue; } - plist_print(fileData); const std::string wifiMacAddress = PlistNavigator(fileData)["WiFiMACAddress"].getString(); + // FIXME: free ? // plist_free(fileData); bool isCompatible = !wifiMacAddress.empty(); // TODO: !important invalidate expired pairing files @@ -98,13 +98,11 @@ void AppContext::cachePairedDevices() auto conn = UsbmuxdConnection::default_new(0); if (conn.is_err()) { qDebug() << "ERROR: Failed to connect to usbmuxd!"; - // return 1; } auto devices = conn.unwrap().get_devices(); if (devices.is_err()) { qDebug() << "ERROR: Failed to get device list!"; - // return 1; } for (const auto &device : devices.unwrap()) { @@ -142,11 +140,14 @@ void AppContext::cachePairedDevices() if (mac_address) { qDebug() << "Adding to cache" << QString::fromUtf8(mac_address); + QString path = QString::fromStdString( + "/var/db/lockdown/" + udid.unwrap() + + ".plist"); + SettingsManager::sharedInstance() + ->setIdeviceDefaultPairingFile( + QString::fromUtf8(mac_address), path); m_pairingFileCache[QString::fromUtf8( - mac_address)] = - QString::fromStdString("/var/db/lockdown/" + - udid.unwrap() + - ".plist"); + mac_address)] = path; free(mac_address); } } @@ -155,12 +156,6 @@ void AppContext::cachePairedDevices() } free(plist_data); } - // qDebug() << "Wireless device UDID:" - // << QString::fromStdString(udid.unwrap()) - // << "Pairing file retrieval" - // << (error == nullptr - // ? "succeeded" - // : QString::fromStdString(error->message)); // Clean up // idevice_pairing_file_free(pairing_file.unwrap().raw()); } @@ -172,6 +167,19 @@ void AppContext::cachePairedDevices() } } } + + // sometimes macOS doesn't find the network iDevice even tho we can connect + // if we know the ip address + QMap cachedPairingFiles = + SettingsManager::sharedInstance()->getAllIdeviceDefaultPairingFiles(); + + for (const QString &mac : cachedPairingFiles.keys()) { + const QString path = cachedPairingFiles.value(mac); + qDebug() << "Using pairing file for MAC:" << mac + << "cached from settings"; + m_pairingFileCache[mac] = path; + } + #endif } @@ -181,6 +189,7 @@ void AppContext::addDevice(QString udid, QString ipAddress) { + emit initStarted(udid); try { // iDescriptorInitDeviceResult initResult; auto initResult = std::make_shared(); diff --git a/src/appcontext.h b/src/appcontext.h index 40f8c17..52cd902 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -75,6 +75,7 @@ signals: // only fired on wireless devices when we have no pairing file for them void noPairingFileForWirelessDevice(const QString &macAddress); void initFailed(const QString &udid); + void initStarted(const QString &udid); void systemSleepStarting(); void systemWakeup(); diff --git a/src/networkdevicestoconnectwidget.cpp b/src/networkdevicestoconnectwidget.cpp index cecd186..3c89b96 100644 --- a/src/networkdevicestoconnectwidget.cpp +++ b/src/networkdevicestoconnectwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include NetworkDeviceCard::NetworkDeviceCard(const NetworkDevice &device, QWidget *parent) @@ -117,6 +118,25 @@ void NetworkDeviceCard::failed() }); } +void NetworkDeviceCard::noPairingFile() +{ + // TODO: add a button or hint to explain how to create a pairing file for + // this device + m_connectButton->setText("No pairing file"); + m_connectButton->setEnabled(false); + + QTimer::singleShot(5000, this, [this]() { + m_connectButton->setText("Connect"); + m_connectButton->setEnabled(true); + }); +} + +void NetworkDeviceCard::initStarted() +{ + m_connectButton->setText("Connecting..."); + m_connectButton->setEnabled(false); +} + NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent) : QWidget(parent) { @@ -147,6 +167,8 @@ NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent) &NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice); connect(AppContext::sharedInstance(), &AppContext::initFailed, this, &NetworkDevicesToConnectWidget::onDeviceInitFailed); + connect(AppContext::sharedInstance(), &AppContext::initStarted, this, + &NetworkDevicesToConnectWidget::onDeviceInitStarted); } NetworkDevicesToConnectWidget::~NetworkDevicesToConnectWidget() @@ -284,7 +306,11 @@ void NetworkDevicesToConnectWidget::onWirelessDeviceRemoved( void NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice( const QString &macAddress) { - // m_deviceCards. + NetworkDeviceCard *deviceCard = m_deviceCards[macAddress]; + if (deviceCard) { + qDebug() << "Calling noPairingFile() on device card for" << macAddress; + deviceCard->noPairingFile(); + } } // udid or mac address @@ -295,4 +321,13 @@ void NetworkDevicesToConnectWidget::onDeviceInitFailed(const QString &udid) qDebug() << "Calling failed() on device card for" << udid; deviceCard->failed(); } +} + +void NetworkDevicesToConnectWidget::onDeviceInitStarted(const QString &udid) +{ + NetworkDeviceCard *deviceCard = m_deviceCards[udid]; + if (deviceCard) { + qDebug() << "Calling initStarted() on device card for" << udid; + deviceCard->initStarted(); + } } \ No newline at end of file diff --git a/src/networkdevicestoconnectwidget.h b/src/networkdevicestoconnectwidget.h index 5536495..90959c9 100644 --- a/src/networkdevicestoconnectwidget.h +++ b/src/networkdevicestoconnectwidget.h @@ -20,6 +20,8 @@ #ifndef NETWORKDEVICESTOCONNECTWIDGET_H #define NETWORKDEVICESTOCONNECTWIDGET_H +#include "iDescriptor-ui.h" + #ifdef __linux__ #include "core/services/avahi/avahi_service.h" #else @@ -45,6 +47,8 @@ private: public: void failed(); + void noPairingFile(); + void initStarted(); }; class NetworkDevicesToConnectWidget : public QWidget @@ -60,6 +64,7 @@ private slots: void onWirelessDeviceRemoved(const QString &deviceName); void onNoPairingFileForWirelessDevice(const QString &macAddress); void onDeviceInitFailed(const QString &udid); + void onDeviceInitStarted(const QString &udid); private: void setupUI(); diff --git a/src/servicemanager.cpp b/src/servicemanager.cpp index dc4a3d7..c2c089e 100644 --- a/src/servicemanager.cpp +++ b/src/servicemanager.cpp @@ -180,7 +180,7 @@ IdeviceFfiError *ServiceManager::mountImage(const iDescriptorDevice *device, void ServiceManager::getCableInfo(const iDescriptorDevice *device, plist_t &response) { - executeOperation( + executeVoidOperation( device, [device, &response]() { _get_cable_info(device, response); }); } diff --git a/src/servicemanager.h b/src/servicemanager.h index f1af482..541f9ca 100644 --- a/src/servicemanager.h +++ b/src/servicemanager.h @@ -146,6 +146,31 @@ public: operation(); } + static void + executeVoidOperation(const iDescriptorDevice *device, + std::function operation, + std::optional altAfc = std::nullopt) + { + if (!device) { + return; + } + + std::lock_guard lock(device->mutex); + + // Double-check device is still valid after acquiring lock + if (!device->afcClient) { + return; + } + + if (altAfc && !*altAfc) { + // altAfc was explicitly provided but is null, which is an + // invalid state. + return; + } + + operation(); + } + static IdeviceFfiError *executeAfcOperation( const iDescriptorDevice *device, std::function operation, diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index 65c688b..cbfee40 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -442,4 +442,37 @@ void SettingsManager::setShowV4L2(bool show) m_settings->setValue("showV4L2", show); m_settings->sync(); } +#endif + +/* + only needed on macOS because + we cannot read /var/db/lockdown without root perm + so caching must be implemented +*/ +#ifdef __APPLE__ +void SettingsManager::setIdeviceDefaultPairingFile(const QString &macAddress, + const QString &pairingFile) +{ + m_settings->setValue("_macos_idevice_" + macAddress, pairingFile); + m_settings->sync(); +} + +QString +SettingsManager::getIdeviceDefaultPairingFile(const QString &macAddress) const +{ + return m_settings->value("_macos_idevice_" + macAddress, "").toString(); +} + +QMap SettingsManager::getAllIdeviceDefaultPairingFiles() const +{ + QMap macAddresses; + QStringList allKeys = m_settings->allKeys(); + for (const QString &key : allKeys) { + if (key.startsWith("_macos_idevice_")) { + QString macAddress = key.mid(QString("_macos_idevice_").length()); + macAddresses[macAddress] = m_settings->value(key, "").toString(); + } + } + return macAddresses; +} #endif \ No newline at end of file diff --git a/src/settingsmanager.h b/src/settingsmanager.h index 372ddff..153282a 100644 --- a/src/settingsmanager.h +++ b/src/settingsmanager.h @@ -119,6 +119,14 @@ public: bool showV4L2() const; void setShowV4L2(bool show); #endif + +#ifdef __APPLE__ + void setIdeviceDefaultPairingFile(const QString &macAddress, + const QString &pairingFile); + QString getIdeviceDefaultPairingFile(const QString &macAddress) const; + QMap getAllIdeviceDefaultPairingFiles() const; +#endif + signals: void favoritePlacesChanged(); void recentLocationsChanged();