mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-22 03:45:51 +08:00
migrate to cxx-qt
This commit is contained in:
+103
-302
@@ -38,158 +38,29 @@ AppContext::AppContext(QObject *parent) : QObject{parent}
|
||||
void AppContext::cachePairedDevices()
|
||||
{
|
||||
|
||||
/*
|
||||
does not work on macOS because we cannot read /var/db/lockdown without root
|
||||
perm
|
||||
*/
|
||||
#ifndef __APPLE__
|
||||
QDir lockdowndir(LOCKDOWN_PATH);
|
||||
if (!lockdowndir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Load cached pairing files
|
||||
QStringList pairingFiles =
|
||||
lockdowndir.entryList(QStringList() << "*.plist", QDir::Files);
|
||||
|
||||
qDebug() << "Parsing cached pairing files in /var/lib/lockdown:";
|
||||
for (const QString &fileName : pairingFiles) {
|
||||
qDebug() << "Found pairing file:" << fileName;
|
||||
plist_t fileData = nullptr;
|
||||
plist_read_from_file(
|
||||
lockdowndir.filePath(fileName).toUtf8().constData(), &fileData,
|
||||
NULL);
|
||||
|
||||
if (!fileData) {
|
||||
continue;
|
||||
}
|
||||
const std::string wifiMacAddress =
|
||||
PlistNavigator(fileData)["WiFiMACAddress"].getString();
|
||||
// FIXME: free ?
|
||||
// plist_free(fileData);
|
||||
bool isCompatible = !wifiMacAddress.empty();
|
||||
// TODO: !important invalidate expired pairing files
|
||||
// sometimes there is no WiFiMACAddress
|
||||
if (!isCompatible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_pairingFileCache[QString::fromStdString(wifiMacAddress)] =
|
||||
lockdowndir.filePath(fileName);
|
||||
}
|
||||
#else
|
||||
/* MacOS */
|
||||
qDebug() << "Caching paired network devices from usbmuxd";
|
||||
auto conn = UsbmuxdConnection::default_new(0);
|
||||
if (conn.is_err()) {
|
||||
qDebug() << "ERROR: Failed to connect to usbmuxd!";
|
||||
return;
|
||||
}
|
||||
|
||||
auto devices = conn.unwrap().get_devices();
|
||||
if (devices.is_err()) {
|
||||
qDebug() << "ERROR: Failed to get device list!";
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &device : devices.unwrap()) {
|
||||
auto conn_type = device.get_connection_type();
|
||||
if (conn_type.is_some() &&
|
||||
conn_type.unwrap().to_string() == "Network") {
|
||||
auto udid = device.get_udid();
|
||||
if (udid.is_some()) {
|
||||
qDebug() << "Found network device with UDID:"
|
||||
<< QString::fromStdString(udid.unwrap());
|
||||
|
||||
auto pairing_file =
|
||||
conn.unwrap().get_pair_record(udid.unwrap());
|
||||
|
||||
uint8_t *plist_data = nullptr;
|
||||
size_t plist_size = 0;
|
||||
IdeviceFfiError *error = idevice_pairing_file_serialize(
|
||||
pairing_file.unwrap().raw(), &plist_data, &plist_size);
|
||||
|
||||
if (error == nullptr) {
|
||||
plist_t root_node = nullptr;
|
||||
plist_from_xml((const char *)plist_data, plist_size,
|
||||
&root_node);
|
||||
|
||||
if (root_node) {
|
||||
plist_t wifi_mac_node =
|
||||
plist_dict_get_item(root_node, "WiFiMACAddress");
|
||||
|
||||
if (wifi_mac_node &&
|
||||
plist_get_node_type(wifi_mac_node) ==
|
||||
PLIST_STRING) {
|
||||
char *mac_address = nullptr;
|
||||
plist_get_string_val(wifi_mac_node, &mac_address);
|
||||
|
||||
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)] = path;
|
||||
plist_mem_free(mac_address);
|
||||
}
|
||||
}
|
||||
|
||||
plist_free(root_node);
|
||||
}
|
||||
plist_mem_free(plist_data);
|
||||
}
|
||||
// Clean up
|
||||
// idevice_pairing_file_free(pairing_file.unwrap().raw());
|
||||
}
|
||||
} else if (conn_type.is_some()) {
|
||||
auto udid = device.get_udid();
|
||||
if (udid.is_some()) {
|
||||
qDebug() << "Found USB device with UDID:"
|
||||
<< QString::fromStdString(udid.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sometimes macOS doesn't find the network iDevice even tho we can connect
|
||||
// if we know the ip address
|
||||
QMap<QString, QString> 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
|
||||
m_pairingFileCache = core->get_pairing_files();
|
||||
}
|
||||
|
||||
void AppContext::addDevice(iDescriptor::Uniq uniq,
|
||||
iDescriptor::IdeviceConnectionType conn_type,
|
||||
AddType addType, QString wifiMacAddress,
|
||||
QString ipAddress)
|
||||
AddType addType, QString info,
|
||||
QString wifiMacAddress, QString ipAddress)
|
||||
{
|
||||
|
||||
if (QCoreApplication::closingDown()) {
|
||||
qDebug() << "Ignoring addDevice during shutdown for" << uniq.get();
|
||||
return;
|
||||
}
|
||||
emit initStarted(uniq);
|
||||
|
||||
const iDescriptorDevice *existingDevice = nullptr;
|
||||
existingDevice = getDeviceByMacAddress(uniq.get());
|
||||
std::shared_ptr<iDescriptorDevice> existingDevice = nullptr;
|
||||
// existingDevice = getDeviceByMacAddress(uniq.get());
|
||||
if (!existingDevice) {
|
||||
existingDevice = getDevice(uniq.get().toStdString());
|
||||
existingDevice = getDevice(uniq.get());
|
||||
}
|
||||
|
||||
if (existingDevice) {
|
||||
emit deviceAlreadyExists(uniq);
|
||||
uniq.isMac() ? emit deviceAlreadyExistsMAC(uniq)
|
||||
: emit deviceAlreadyExists(uniq);
|
||||
// TODO: add a setting for this
|
||||
|
||||
setCurrentDeviceSelection(DeviceSelection(existingDevice->udid), true);
|
||||
@@ -197,126 +68,63 @@ void AppContext::addDevice(iDescriptor::Uniq uniq,
|
||||
}
|
||||
|
||||
if (addType == AddType::Pairing) {
|
||||
handlePairing(uniq, true);
|
||||
// handlePairing(uniq, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addType == AddType::FailedToPair) {
|
||||
// FIXME: no widget is listening for this signal for now
|
||||
emit pairingFailed(uniq);
|
||||
// emit pairingFailed(uniq);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto initResult = std::make_shared<iDescriptorInitDeviceResult>();
|
||||
qDebug() << "Device initialized: " << uniq;
|
||||
|
||||
QFuture<void> future = QtConcurrent::run([this, uniq, conn_type,
|
||||
addType, wifiMacAddress,
|
||||
ipAddress, initResult]() {
|
||||
if (addType == AddType::UpgradeToWireless) {
|
||||
// FIXME: wireless pairing is supported iOS 14+
|
||||
// we can ignore devices that don't support it,
|
||||
qDebug() << "AddType::UpgradeToWireless";
|
||||
const QString _pairingFilePath = getCachedPairingFile(uniq);
|
||||
|
||||
if (_pairingFilePath.isEmpty()) {
|
||||
qDebug() << "Cannot upgrade to wireless, no cached pairing "
|
||||
"file for"
|
||||
<< uniq;
|
||||
emitNoPairingFileForWirelessDevice(uniq);
|
||||
return;
|
||||
}
|
||||
|
||||
init_idescriptor_device(uniq, *initResult,
|
||||
{ipAddress, _pairingFilePath});
|
||||
|
||||
} else if (addType == AddType::Wireless) {
|
||||
qDebug() << "AddType::Wireless";
|
||||
const QString _pairingFilePath = getCachedPairingFile(uniq);
|
||||
|
||||
if (_pairingFilePath.isEmpty()) {
|
||||
qDebug() << "Cannot upgrade to wireless, no cached pairing "
|
||||
"file for"
|
||||
<< uniq;
|
||||
emitNoPairingFileForWirelessDevice(uniq);
|
||||
return;
|
||||
}
|
||||
|
||||
init_idescriptor_device(uniq, *initResult,
|
||||
{ipAddress, _pairingFilePath});
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
qDebug() << "AddType::Regular";
|
||||
init_idescriptor_device(uniq, *initResult, {nullptr, nullptr});
|
||||
}
|
||||
});
|
||||
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
|
||||
watcher->setFuture(future);
|
||||
connect(
|
||||
watcher, &QFutureWatcher<void>::finished, this,
|
||||
[this, uniq, initResult, addType, conn_type, watcher]() mutable {
|
||||
watcher->deleteLater();
|
||||
qDebug() << "init_idescriptor_device success ?: "
|
||||
<< initResult->success;
|
||||
if (!initResult->success) {
|
||||
emit initFailed(uniq);
|
||||
if (initResult->error) {
|
||||
// Handle if it's a pairing related error
|
||||
const auto code = initResult->error->code;
|
||||
if (code == PairingDialogResponsePending ||
|
||||
code == InvalidHostID ||
|
||||
code == PasswordProtected) {
|
||||
handlePairing(uniq, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// FIXME: warn
|
||||
return;
|
||||
}
|
||||
qDebug() << "Device initialized: " << uniq;
|
||||
|
||||
if (m_pendingDevices.contains(uniq)) {
|
||||
qDebug() << "Removing from pending devices: " << uniq;
|
||||
m_pendingDevices.removeAll(uniq);
|
||||
emit devicePairingExpired(uniq);
|
||||
}
|
||||
|
||||
iDescriptorDevice *device = new iDescriptorDevice{
|
||||
.udid = initResult->deviceInfo.UniqueDeviceID,
|
||||
.conn_type = conn_type,
|
||||
.provider = initResult->provider,
|
||||
.deviceInfo = initResult->deviceInfo,
|
||||
.afcClient = initResult->afcClient,
|
||||
.afc2Client = initResult->afc2Client,
|
||||
.lockdown = initResult->lockdown,
|
||||
.diagRelay = initResult->diagRelay,
|
||||
.heartbeatThread = initResult->heartbeatThread};
|
||||
|
||||
if (initResult->deviceInfo.isWireless &&
|
||||
initResult->heartbeatThread) {
|
||||
device->heartbeatThread->start();
|
||||
}
|
||||
|
||||
m_devices[device->udid] = device;
|
||||
|
||||
if (addType == AddType::Wireless ||
|
||||
addType == AddType::UpgradeToWireless ||
|
||||
addType == AddType::Regular) {
|
||||
qDebug() << "Wireless device added: " << uniq;
|
||||
|
||||
emit deviceAdded(device);
|
||||
emit deviceChange();
|
||||
return;
|
||||
}
|
||||
emit devicePaired(device);
|
||||
emit deviceChange();
|
||||
m_pendingDevices.removeAll(uniq);
|
||||
});
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "Exception in onDeviceAdded: " << e.what();
|
||||
if (m_pendingDevices.contains(uniq)) {
|
||||
qDebug() << "Removing from pending devices: " << uniq;
|
||||
m_pendingDevices.removeAll(uniq);
|
||||
emit devicePairingExpired(uniq);
|
||||
}
|
||||
|
||||
pugi::xml_document doc;
|
||||
auto res = doc.load_string(info.toUtf8().constData());
|
||||
if (!res) {
|
||||
core->remove_device(uniq);
|
||||
QMessageBox::warning(nullptr, "Failed to add device",
|
||||
"Failed to parse device info XML for device " +
|
||||
uniq.get() +
|
||||
". The device may not function "
|
||||
"correctly. Please report this issue.");
|
||||
qWarning() << "Failed to parse device info XML for" << uniq << ":"
|
||||
<< res.description();
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceInfo deviceInfo;
|
||||
fullDeviceInfo(doc, deviceInfo);
|
||||
|
||||
const iDescriptorDevice device = {
|
||||
.udid = uniq.get(),
|
||||
.conn_type = conn_type,
|
||||
.deviceInfo = deviceInfo,
|
||||
.ios_version = deviceInfo.parsedDeviceVersion.major,
|
||||
.service_manager = new CXX::ServiceManager(
|
||||
uniq.get(), deviceInfo.parsedDeviceVersion.major),
|
||||
.afc_backend = new CXX::AfcBackend(uniq.get())};
|
||||
|
||||
m_devices[device.udid] = std::make_shared<iDescriptorDevice>(device);
|
||||
|
||||
if (addType == AddType::Wireless || addType == AddType::UpgradeToWireless ||
|
||||
addType == AddType::Regular) {
|
||||
qDebug() << "Wireless device added: " << uniq;
|
||||
|
||||
emit deviceAdded(m_devices[device.udid]);
|
||||
emit deviceChange();
|
||||
return;
|
||||
}
|
||||
emit devicePaired(m_devices[device.udid]);
|
||||
emit deviceChange();
|
||||
m_pendingDevices.removeAll(uniq);
|
||||
}
|
||||
|
||||
int AppContext::getConnectedDeviceCount() const
|
||||
@@ -328,23 +136,12 @@ int AppContext::getConnectedDeviceCount() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppContext::removeDevice(iDescriptor::Uniq uniq)
|
||||
void AppContext::removeDevice(iDescriptor::Uniq uniq, bool ask_backend)
|
||||
{
|
||||
qDebug() << "AppContext::removeDevice device with"
|
||||
<< (uniq.isMac() ? "MAC" : "UDID") << uniq.get();
|
||||
|
||||
std::string udid = uniq.isUdid() ? uniq.get().toStdString() : "";
|
||||
QString q_udid = QString::fromStdString(udid);
|
||||
|
||||
if (uniq.isMac()) {
|
||||
const iDescriptorDevice *device = getDeviceByMacAddress(uniq.get());
|
||||
if (device) {
|
||||
udid = device->udid;
|
||||
q_udid = QString::fromStdString(udid);
|
||||
} else {
|
||||
qDebug() << "Device with MAC " << uniq << " not found.";
|
||||
}
|
||||
}
|
||||
QString q_udid = uniq.get();
|
||||
|
||||
if (m_pendingDevices.contains(q_udid)) {
|
||||
m_pendingDevices.removeAll(q_udid);
|
||||
@@ -356,27 +153,23 @@ void AppContext::removeDevice(iDescriptor::Uniq uniq)
|
||||
" not found in pending devices.";
|
||||
}
|
||||
|
||||
if (!m_devices.contains(udid)) {
|
||||
if (!m_devices.contains(q_udid)) {
|
||||
qDebug() << "Device with UUID " + q_udid +
|
||||
" not found in normal devices.";
|
||||
return;
|
||||
}
|
||||
|
||||
iDescriptorDevice *device = m_devices[udid];
|
||||
m_devices.remove(udid);
|
||||
auto device = m_devices[q_udid];
|
||||
m_devices.remove(q_udid);
|
||||
|
||||
emit deviceRemoved(udid, device->deviceInfo.wifiMacAddress,
|
||||
emit deviceRemoved(q_udid, device->deviceInfo.wifiMacAddress,
|
||||
device->deviceInfo.ipAddress,
|
||||
device->deviceInfo.isWireless);
|
||||
emit deviceChange();
|
||||
|
||||
qDebug() << "Waiting to acquire lock for device cleanup: "
|
||||
<< QString::fromStdString(udid);
|
||||
std::lock_guard<std::recursive_mutex> lock(device->mutex);
|
||||
qDebug() << "Acquired lock, cleaning up device: "
|
||||
<< QString::fromStdString(udid);
|
||||
|
||||
freeDevice(device);
|
||||
if (ask_backend) {
|
||||
core->remove_device(q_udid);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT
|
||||
@@ -402,12 +195,16 @@ void AppContext::removeRecoveryDevice(uint64_t ecid)
|
||||
}
|
||||
#endif
|
||||
|
||||
iDescriptorDevice *AppContext::getDevice(const std::string &uniq)
|
||||
std::shared_ptr<iDescriptorDevice> AppContext::getDevice(const QString &uniq)
|
||||
{
|
||||
return m_devices.value(uniq, nullptr);
|
||||
auto it = m_devices.find(uniq);
|
||||
if (it != m_devices.end()) {
|
||||
return it.value();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QList<iDescriptorDevice *> AppContext::getAllDevices()
|
||||
QList<std::shared_ptr<iDescriptorDevice>> AppContext::getAllDevices()
|
||||
{
|
||||
return m_devices.values();
|
||||
}
|
||||
@@ -468,7 +265,7 @@ void AppContext::addRecoveryDevice(uint64_t ecid)
|
||||
AppContext::~AppContext()
|
||||
{
|
||||
for (auto device : m_devices) {
|
||||
freeDevice(device);
|
||||
// freeDevice(device);
|
||||
}
|
||||
|
||||
m_devices.clear();
|
||||
@@ -510,9 +307,9 @@ const DeviceSelection &AppContext::getCurrentDeviceSelection() const
|
||||
const iDescriptorDevice *
|
||||
AppContext::getDeviceByMacAddress(const QString &macAddress) const
|
||||
{
|
||||
for (const iDescriptorDevice *device : m_devices) {
|
||||
for (const auto &device : m_devices) {
|
||||
if (device->deviceInfo.wifiMacAddress == macAddress.toStdString()) {
|
||||
return device;
|
||||
return device.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -528,7 +325,7 @@ const QString AppContext::getCachedPairingFile(const QString &uniq) const
|
||||
QString pairingFile;
|
||||
|
||||
if (m_pairingFileCache.contains(uniq)) {
|
||||
pairingFile = m_pairingFileCache.value(uniq);
|
||||
pairingFile = m_pairingFileCache.value(uniq).toString();
|
||||
}
|
||||
return pairingFile;
|
||||
}
|
||||
@@ -540,42 +337,46 @@ void AppContext::heartbeatFailed(const QString &macAddress, int tries)
|
||||
|
||||
void AppContext::tryToConnectToNetworkDevice(const NetworkDevice &device)
|
||||
{
|
||||
qDebug() << "Trying to connect to network device with MAC:"
|
||||
<< device.macAddress << "IP:" << device.address;
|
||||
|
||||
// force refresh macAddress-pairing file mapping
|
||||
cachePairedDevices();
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection,
|
||||
Q_ARG(iDescriptor::Uniq, iDescriptor::Uniq(device.macAddress, true)),
|
||||
Q_ARG(iDescriptor::IdeviceConnectionType,
|
||||
iDescriptor::CONNECTION_NETWORK),
|
||||
Q_ARG(AddType, AddType::Wireless), Q_ARG(QString, device.macAddress),
|
||||
Q_ARG(QString, device.address));
|
||||
const iDescriptorDevice *existingDevice = nullptr;
|
||||
existingDevice = getDeviceByMacAddress(device.macAddress);
|
||||
|
||||
if (existingDevice) {
|
||||
emit deviceAlreadyExistsMAC(
|
||||
iDescriptor::Uniq(existingDevice->deviceInfo.wifiMacAddress, true));
|
||||
// TODO: add a setting for this
|
||||
|
||||
setCurrentDeviceSelection(DeviceSelection(existingDevice->udid), true);
|
||||
return;
|
||||
}
|
||||
|
||||
cachePairedDevices();
|
||||
QString pairing_file = getCachedPairingFile(device.macAddress);
|
||||
if (pairing_file.isEmpty()) {
|
||||
qDebug() << "No pairing file cached for device with MAC:"
|
||||
<< device.macAddress
|
||||
<< "Emitting noPairingFileForWirelessDevice event";
|
||||
emitNoPairingFileForWirelessDevice(device.macAddress);
|
||||
return;
|
||||
}
|
||||
core->init_wireless_device(device.address,
|
||||
LOCKDOWN_PATH + QString("/") + pairing_file,
|
||||
device.macAddress);
|
||||
}
|
||||
|
||||
// this is required because cannot emit signals from qfuture
|
||||
void AppContext::emitNoPairingFileForWirelessDevice(const QString &udid)
|
||||
{
|
||||
emit noPairingFileForWirelessDevice(udid);
|
||||
}
|
||||
|
||||
void AppContext::freeDevice(iDescriptorDevice *device)
|
||||
void AppContext::emitInitStarted(const QString &macAddress)
|
||||
{
|
||||
if (device->afcClient)
|
||||
afc_client_free(device->afcClient);
|
||||
if (device->afc2Client)
|
||||
afc_client_free(device->afc2Client);
|
||||
|
||||
if (device->heartbeatThread) {
|
||||
device->heartbeatThread->requestInterruption();
|
||||
device->heartbeatThread->wait();
|
||||
delete device->heartbeatThread;
|
||||
}
|
||||
|
||||
lockdownd_client_free(device->lockdown);
|
||||
idevice_provider_free(device->provider);
|
||||
delete device;
|
||||
device = nullptr;
|
||||
emit initStarted(macAddress);
|
||||
}
|
||||
|
||||
void AppContext::handlePairing(iDescriptor::Uniq uniq, bool timeout)
|
||||
|
||||
Reference in New Issue
Block a user