From c0995006afd472e1f264d568e76b3f7fd682625a Mon Sep 17 00:00:00 2001 From: uncor3 Date: Sun, 21 Dec 2025 05:34:08 +0000 Subject: [PATCH] WIP: migrate to idevice-rs --- .gitmodules | 3 + .vscode/c_cpp_properties.json | 50 +- .vscode/settings.json | 6 +- CMakeLists.txt | 331 ++++++++---- README.md | 21 +- lib/idevice-rs | 1 + src/afcexplorerwidget.cpp | 2 - src/afcexplorerwidget.h | 3 +- src/appcontext.cpp | 457 ++++++++++------ src/appcontext.h | 34 +- src/core/services/avahi/avahi_service.cpp | 5 +- src/core/services/detect_jailbroken.cpp | 21 +- src/core/services/get-device-info.cpp | 34 +- src/core/services/get_battery_info.cpp | 58 ++- src/core/services/init_device.cpp | 437 +++++++++++----- src/deviceimagewidget.cpp | 6 +- src/deviceinfowidget.cpp | 134 ++--- src/devicemanagerwidget.cpp | 233 +++++---- src/devicemanagerwidget.h | 25 +- src/devicemenuwidget.cpp | 42 +- src/devicemenuwidget.h | 10 +- src/devicemonitor.h | 126 +++++ src/diskusagewidget.cpp | 203 ++++---- src/fileexplorerwidget.cpp | 2 - src/fileexplorerwidget.h | 3 +- src/iDescriptor.h | 291 ++++++----- src/main.cpp | 14 +- src/mainwindow.cpp | 601 ++++++++++++++-------- src/mainwindow.h | 10 +- src/networkdevicemanager.cpp | 28 + src/networkdevicemanager.h | 29 ++ 31 files changed, 2024 insertions(+), 1196 deletions(-) create mode 160000 lib/idevice-rs create mode 100644 src/devicemonitor.h create mode 100644 src/networkdevicemanager.cpp create mode 100644 src/networkdevicemanager.h diff --git a/.gitmodules b/.gitmodules index 1e3396f..13c8d2e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "lib/win-ifuse"] path = lib/win-ifuse url = https://github.com/uncor3/win-ifuse.git +[submodule "lib/idevice-rs"] + path = lib/idevice-rs + url = https://github.com/jkcoxson/idevice.git diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 0b6e02f..cc09ba3 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,25 +1,27 @@ { - "configurations": [ - { - "name": "Linux", - "includePath": [ - "${workspaceFolder}/**", - "/usr/include/qt/**", - "/usr/local/opt/qt/**", - "${workspaceFolder}/build/Desktop-Debug/iDescriptor_autogen/include", - "${workspaceFolder}/build/Desktop-Debug/src/lib/**", - "/usr/local/include/**", - "/usr/include/qt6/**", - "/usr/include/qt6/QtBluetooth/**", - "${workspaceFolder}/lib/zupdater/src", - "/usr/include/qt6/QtConcurrent" - ], - "defines": [], - "compilerPath": "/usr/bin/gcc", - "cStandard": "c17", - "cppStandard": "gnu++17", - "intelliSenseMode": "linux-gcc-x64" - } - ], - "version": 4 -} \ No newline at end of file + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/usr/include/qt/**", + "/usr/local/opt/qt/**", + "${workspaceFolder}/build/Desktop-Debug/iDescriptor_autogen/include", + "${workspaceFolder}/build/Desktop-Debug/src/lib/**", + "/usr/local/include/**", + "/usr/include/qt6/**", + "/usr/include/qt6/QtBluetooth/**", + "${workspaceFolder}/lib/zupdater/src", + "/usr/include/qt6/QtConcurrent", + "/usr/include/qt6", + "${workspaceFolder}/build/Desktop-Release/iDescriptor_autogen/include" + ], + "defines": ["APP_VERSION=\"\""], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c17", + "cppStandard": "gnu++17", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ec39cc..d6a8410 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -202,6 +202,10 @@ "qimage": "cpp", "qabstractbutton": "cpp", "qtnetwork": "cpp", - "qtcore": "cpp" + "qtcore": "cpp", + "csetjmp": "cpp", + "qthread": "cpp", + "qregularexpression": "cpp", + "qnetworkaccessmanager": "cpp" } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d2d993..7c794b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,43 +19,42 @@ if (APPLE) endif() # Platform-specific paths for libraries built from source -if(WIN32) - include_directories("C:/msys64/mingw64/include") - link_directories("C:/msys64/mingw64/lib") - set(PKG_CONFIG_EXECUTABLE "C:/msys64/mingw64/bin/pkg-config.exe") - list(APPEND CMAKE_PREFIX_PATH "C:/lxqt") - set(CUSTOM_LIB_PATH "C:/msys64/mingw64/lib") - set(CUSTOM_INCLUDE_PATH "C:/msys64/mingw64/include") - set(CUSTOM_PKGCONFIG_PATH "C:/msys64/mingw64/lib/pkgconfig") - set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH};$ENV{PKG_CONFIG_PATH}") -elseif(APPLE) - set(CUSTOM_LIB_PATH "/usr/local/lib") - set(CUSTOM_INCLUDE_PATH "/usr/local/include") - set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") - set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH}:$ENV{PKG_CONFIG_PATH}") -else () - set(CUSTOM_LIB_PATH "/usr/local/lib") - set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") - set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CUSTOM_PKGCONFIG_PATH}") -endif() +# if(WIN32) +# include_directories("C:/msys64/mingw64/include") +# link_directories("C:/msys64/mingw64/lib") +# set(PKG_CONFIG_EXECUTABLE "C:/msys64/mingw64/bin/pkg-config.exe") +# list(APPEND CMAKE_PREFIX_PATH "C:/lxqt") +# set(CUSTOM_LIB_PATH "C:/msys64/mingw64/lib") +# set(CUSTOM_INCLUDE_PATH "C:/msys64/mingw64/include") +# set(CUSTOM_PKGCONFIG_PATH "C:/msys64/mingw64/lib/pkgconfig") +# set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH};$ENV{PKG_CONFIG_PATH}") +# elseif(APPLE) +# set(CUSTOM_LIB_PATH "/usr/local/lib") +# # Remove the problematic include path that's causing conflicts +# # set(CUSTOM_INCLUDE_PATH "/usr/local/include") +# set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") +# set(ENV{PKG_CONFIG_PATH} "${CUSTOM_PKGCONFIG_PATH}:$ENV{PKG_CONFIG_PATH}") +# else () +# set(CUSTOM_LIB_PATH "/usr/local/lib") +# set(CUSTOM_PKGCONFIG_PATH "/usr/local/lib/pkgconfig") +# set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CUSTOM_PKGCONFIG_PATH}") +# endif() -include_directories(${CUSTOM_INCLUDE_PATH}) +# foreach(_ IN LISTS CMAKE_PREFIX_PATH) +# list(APPEND _qt_pkg_dirs +# "${_}/lib/pkgconfig" +# "${_}/lib64/pkgconfig" +# "${_}/lib64/qt/pkgconfig" +# "${_}/lib/qt/pkgconfig" +# ) +# endforeach() -foreach(_ IN LISTS CMAKE_PREFIX_PATH) - list(APPEND _qt_pkg_dirs - "${_}/lib/pkgconfig" - "${_}/lib64/pkgconfig" - "${_}/lib64/qt/pkgconfig" - "${_}/lib/qt/pkgconfig" - ) -endforeach() - - -list(APPEND _qt_pkg_dirs ${CUSTOM_PKGCONFIG_PATH}) +# list(APPEND _qt_pkg_dirs ${CUSTOM_PKGCONFIG_PATH}) find_package(PkgConfig REQUIRED) find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets Network QuickControls2 SerialPort Positioning Location QuickWidgets) +find_package(Qt6 REQUIRED COMPONENTS Core) # Add QTermWidget # Prefer CMake-native qtermwidget6, fallback to pkg-config if needed @@ -84,36 +83,86 @@ if(WIN32) message(STATUS "Found Qt bin directory: ${QT_BIN_PATH}") endif() -# Define library search behavior based on platform -if(LINUX) - # On Linux (AUR builds), let CMake search default system paths first. - # The custom path /usr/local/lib will be checked if it's in the default search paths. - set(CUSTOM_FIND_LIB_ARGS "") -else() - # On other platforms, only search the custom path for our specific libraries. - set(CUSTOM_FIND_LIB_ARGS - PATHS ${CUSTOM_LIB_PATH} - NO_DEFAULT_PATH +#------------- IDEVICE-RS INTEGRATION ------------- + +find_program(CARGO_EXECUTABLE cargo REQUIRED) +message(STATUS "Using idevice-rs Rust implementation") + +set(IDEVICE_RS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/idevice-rs) +set(IDEVICE_RS_LIB_PATH ${IDEVICE_RS_SOURCE_DIR}/target/release/libidevice_ffi.a) + +# This command builds the Rust library and declares its output file. +# Any target that uses this output file will automatically depend on this command. +add_custom_command( + OUTPUT ${IDEVICE_RS_LIB_PATH} + COMMAND ${CARGO_EXECUTABLE} build --release --manifest-path ${IDEVICE_RS_SOURCE_DIR}/Cargo.toml + WORKING_DIRECTORY ${IDEVICE_RS_SOURCE_DIR} + COMMENT "Building idevice-rs FFI library" + VERBATIM +) + +# This custom target provides a name to build the Rust library explicitly. +# It depends on the output file, ensuring the custom command is run. +add_custom_target(idevice_rs_build DEPENDS ${IDEVICE_RS_LIB_PATH}) + +# Create an imported target for the Rust static library +add_library(idevice_ffi STATIC IMPORTED GLOBAL) +set_target_properties(idevice_ffi PROPERTIES + IMPORTED_LOCATION "${IDEVICE_RS_LIB_PATH}" +) + +# ---- Build the idevice-rs C++ wrapper library ------------------------------ +set(IDEVICE_CPP_SRC_DIR ${IDEVICE_RS_SOURCE_DIR}/cpp/src) +set(IDEVICE_CPP_INCLUDE_DIR ${IDEVICE_RS_SOURCE_DIR}/cpp/include) +set(IDEVICE_FFI_INCLUDE_DIR ${IDEVICE_RS_SOURCE_DIR}/ffi) +set(PLIST_CPP_INCLUDE_DIR ${IDEVICE_RS_SOURCE_DIR}/plist_ffi/cpp/include) +set(PLIST_CPP_SRC_DIR ${IDEVICE_RS_SOURCE_DIR}/plist_ffi/cpp/src) + +# Collect C++ sources for the wrapper library +file(GLOB_RECURSE IDEVICE_CPP_SOURCES + "${IDEVICE_CPP_SRC_DIR}/*.cpp" +) +file(GLOB PLIST_CPP_SOURCES + "${PLIST_CPP_SRC_DIR}/*.cpp" +) + +add_library(idevice_cpp STATIC ${IDEVICE_CPP_SOURCES} ${PLIST_CPP_SOURCES}) + +target_include_directories(idevice_cpp PUBLIC + ${IDEVICE_CPP_INCLUDE_DIR} + ${PLIST_CPP_INCLUDE_DIR} + PRIVATE + ${IDEVICE_FFI_INCLUDE_DIR} +) + +# Link idevice_cpp to idevice_ffi and add platform-specific dependencies +find_package(Threads REQUIRED) +target_link_libraries(idevice_cpp PUBLIC idevice_ffi Threads::Threads) + +if (UNIX AND NOT APPLE) + pkg_check_modules(UDEV REQUIRED IMPORTED_TARGET udev) + target_link_libraries(idevice_cpp PUBLIC PkgConfig::UDEV dl m) +elseif(APPLE) + find_library(COREFOUNDATION_FRAMEWORK CoreFoundation REQUIRED) + find_library(IOKIT_FRAMEWORK IOKit REQUIRED) + target_link_libraries(idevice_cpp PUBLIC + ${COREFOUNDATION_FRAMEWORK} + ${IOKIT_FRAMEWORK} + "-framework Security" + "-framework SystemConfiguration" + "-framework CoreServices" + "-framework CFNetwork" ) +elseif(WIN32) + target_link_libraries(idevice_cpp PUBLIC ws2_32 userenv.lib ntdll bcrypt) endif() -find_library(IMOBILEDEVICE_LIBRARY - NAMES imobiledevice-1.0 - ${CUSTOM_FIND_LIB_ARGS} - REQUIRED -) +# Set up variables for linking and includes for the main iDescriptor target +set(IDEVICE_IMPLEMENTATION_LIBS idevice_cpp) +# The C header file generated by cbindgen lives here +set(IDEVICE_IMPLEMENTATION_INCLUDES ${IDEVICE_RS_SOURCE_DIR}/ffi/include) -find_library(IMOBILEDEVICE_GLUE_LIBRARY - NAMES imobiledevice-glue-1.0 - ${CUSTOM_FIND_LIB_ARGS} - REQUIRED -) - -find_library(TATSU_LIBRARY - NAMES tatsu - ${CUSTOM_FIND_LIB_ARGS} - REQUIRED -) +#-------------------------------------------------------------------------------- # Add QR code generation library pkg_check_modules(QRENCODE REQUIRED IMPORTED_TARGET libqrencode) @@ -126,36 +175,21 @@ pkg_check_modules(AVCODEC REQUIRED IMPORTED_TARGET libavcodec) pkg_check_modules(AVUTIL REQUIRED IMPORTED_TARGET libavutil) pkg_check_modules(SWSCALE REQUIRED IMPORTED_TARGET libswscale) -if(ENABLE_RECOVERY_DEVICE_SUPPORT) - find_library(IRECOVERY_LIBRARY - NAMES irecovery-1.0 - PATHS ${CUSTOM_LIB_PATH} - NO_DEFAULT_PATH - ) - if(IRECOVERY_LIBRARY) - message(STATUS "Building with recovery device support enabled") - else() - message(WARNING "libirecovery not found. Recovery device support will be disabled. This is to be expected if you are installing from Arch AUR.") - set(ENABLE_RECOVERY_DEVICE_SUPPORT OFF) - endif() -else() - message(STATUS "Recovery device support disabled") -endif() - -find_library(USBMUXD_LIBRARY - NAMES usbmuxd-2.0 - ${CUSTOM_FIND_LIB_ARGS} - REQUIRED -) - -if(WIN32) - # On MSYS2, these are found in the standard mingw64 prefix - find_library(SSL_LIBRARY NAMES ssl PATHS C:/msys64/mingw64/lib REQUIRED) - find_library(CRYPTO_LIBRARY NAMES crypto PATHS C:/msys64/mingw64/lib REQUIRED) -else() - find_library(SSL_LIBRARY NAMES ssl REQUIRED) - find_library(CRYPTO_LIBRARY NAMES crypto REQUIRED) -endif() +# if(ENABLE_RECOVERY_DEVICE_SUPPORT) +# find_library(IRECOVERY_LIBRARY +# NAMES irecovery-1.0 +# PATHS ${CUSTOM_LIB_PATH} +# NO_DEFAULT_PATH +# ) +# if(IRECOVERY_LIBRARY) +# message(STATUS "Building with recovery device support enabled") +# else() +# message(WARNING "libirecovery not found. Recovery device support will be disabled. This is to be expected if you are installing from Arch AUR.") +# set(ENABLE_RECOVERY_DEVICE_SUPPORT OFF) +# endif() +# else() +# message(STATUS "Recovery device support disabled") +# endif() # Add libssh for SSH connections pkg_check_modules(SSH REQUIRED IMPORTED_TARGET libssh) @@ -168,15 +202,73 @@ endif() pkg_check_modules(PUGIXML REQUIRED IMPORTED_TARGET pugixml) -pkg_check_modules(USB REQUIRED IMPORTED_TARGET libusb-1.0) -pkg_check_modules(PLIST REQUIRED IMPORTED_TARGET libplist-2.0) file(GLOB PROJECT_SOURCES -src/*.cpp -src/core/helpers/*.cpp -src/core/services/*.cpp -src/*.h +# src/*.cpp +# src/core/helpers/*.cpp +# src/core/services/*.cpp +# src/*.h +src/mainwindow.cpp +src/mainwindow.h +src/devicemonitor.h +src/main.cpp +src/core/services/init_device.cpp +src/core/services/get_battery_info.cpp +src/core/services/detect_jailbroken.cpp +src/appcontext.cpp +src/appcontext.h +src/devicedatabase.cpp +src/devicedatabase.h +src/core/helpers/compare_product_type.cpp +src/welcomewidget.cpp +src/welcomewidget.h +src/ztabwidget.cpp +src/ztabwidget.h +src/devicemanagerwidget.cpp +src/devicemanagerwidget.h +src/responsiveqlabel.cpp +src/responsiveqlabel.h +src/devicesidebarwidget.cpp +src/devicesidebarwidget.h +src/devicemenuwidget.cpp +src/devicemenuwidget.h +src/deviceinfowidget.cpp +src/deviceinfowidget.h +src/batterywidget.cpp +src/batterywidget.h +src/diskusagewidget.cpp +src/diskusagewidget.h +# src/deviceimagewidget.cpp +# src/deviceimagewidget.h +src/iDescriptor-ui.h +src/infolabel.cpp +src/infolabel.h +src/privateinfolabel.cpp +src/privateinfolabel.h +src/qprocessindicator.cpp +src/qprocessindicator.h +src/diagnosewidget.cpp +src/diagnosewidget.h +src/core/services/get-device-info.cpp +src/deviceimagewidget.cpp +src/deviceimagewidget.h +src/settingsmanager.cpp +src/settingsmanager.h +# src/fileexplorerwidget.cpp +# src/fileexplorerwidget.h +src/settingswidget.cpp +src/settingswidget.h +src/ifusemanager.cpp +src/ifusemanager.h +src/ifusediskunmountbutton.cpp +src/ifusediskunmountbutton.h +src/core/services/get_battery_info.cpp +src/networkdeviceswidget.cpp +src/core/services/avahi/avahi_service.h +src/core/services/avahi/avahi_service.cpp +src/networkdevicemanager.cpp +src/networkdevicemanager.h src/*.ui resources.qrc ) @@ -199,12 +291,12 @@ if (WIN32) list(APPEND PROJECT_SOURCES ${WINDOWS_PLATFORM_SOURCES}) endif() -if(LINUX) - list(APPEND PROJECT_SOURCES - src/core/services/avahi/avahi_service.cpp - src/core/services/avahi/avahi_service.h - ) -endif() +# if(LINUX) +# list(APPEND PROJECT_SOURCES +# src/core/services/avahi/avahi_service.cpp +# src/core/services/avahi/avahi_service.h +# ) +# endif() if (NOT ENABLE_RECOVERY_DEVICE_SUPPORT) list(REMOVE_ITEM PROJECT_SOURCES @@ -253,6 +345,9 @@ else() ) endif() +# Make sure idevice_cpp depends on the Rust library being built +add_dependencies(idevice_cpp idevice_rs_build) + target_link_libraries(iDescriptor PRIVATE Qt6::Widgets Qt6::Multimedia @@ -264,17 +359,17 @@ target_link_libraries(iDescriptor PRIVATE Qt6::Positioning Qt6::QuickWidgets Qt6::QuickControls2 - ${IMOBILEDEVICE_LIBRARY} - ${IMOBILEDEVICE_GLUE_LIBRARY} - ${TATSU_LIBRARY} - ${SSL_LIBRARY} - ${CRYPTO_LIBRARY} + # ${IMOBILEDEVICE_LIBRARY} + # ${IMOBILEDEVICE_GLUE_LIBRARY} + # ${TATSU_LIBRARY} + # ${SSL_LIBRARY} + # ${CRYPTO_LIBRARY} PkgConfig::SSH ${SSH_LIBRARY} - ${USBMUXD_LIBRARY} + # ${USBMUXD_LIBRARY} PkgConfig::PUGIXML - PkgConfig::USB - PkgConfig::PLIST + # PkgConfig::USB + # PkgConfig::PLIST PkgConfig::QRENCODE qtermwidget6 PkgConfig::HEIF @@ -286,17 +381,28 @@ target_link_libraries(iDescriptor PRIVATE airplay ipatool-go ZUpdater + ${IDEVICE_IMPLEMENTATION_LIBS} ) -# Conditionally link libirecovery -if(ENABLE_RECOVERY_DEVICE_SUPPORT) - target_link_libraries(iDescriptor PRIVATE ${IRECOVERY_LIBRARY}) -endif() +# # Conditionally link libirecovery +# if(ENABLE_RECOVERY_DEVICE_SUPPORT) +# target_link_libraries(iDescriptor PRIVATE ${IRECOVERY_LIBRARY}) +# endif() target_include_directories(iDescriptor PRIVATE + # Put idevice-rs includes FIRST + ${IDEVICE_CPP_INCLUDE_DIR} + ${IDEVICE_FFI_INCLUDE_DIR} + ${PLIST_CPP_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib/zupdater/src + # System includes last + ${IDEVICE_IMPLEMENTATION_INCLUDES} ) + + +target_include_directories(iDescriptor PRIVATE ${IDEVICE_IMPLEMENTATION_INCLUDES}) + if(APPLE) find_library(CORE_SERVICES_FRAMEWORK CoreServices REQUIRED) target_link_libraries(iDescriptor PRIVATE @@ -323,6 +429,7 @@ if(APPLE) ${SECURITY_FRAMEWORK} ${COREFOUNDATION_FRAMEWORK} ) +target_link_libraries(iDescriptor PRIVATE Qt6::Core) endif() # Add compile definition for source directory @@ -368,7 +475,7 @@ if (UNIX AND NOT APPLE) ) endif() # Add install rules for the project -include(GNUInstallDirs) +# include(GNUInstallDirs) # Install the main executable install(TARGETS iDescriptor diff --git a/README.md b/README.md index 660092c..f8cb09b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# THIS BRANCH IS UNDER DEVELOPMENT + +## Migrating to new backend -> https://github.com/jkcoxson/idevice + +## Only builds on Linux for now +


@@ -58,9 +64,10 @@ - **Installer (.msi)**: Download and run the installer. Recommended for most users. - **Portable (.zip)**: Extract and run `iDescriptor.exe`. No installation required. - **Choco** : + ```bash choco install idescriptor --version=0.1.0 - ``` +``` #### macOS @@ -72,11 +79,13 @@ Open the `.dmg` and drag iDescriptor to Applications. #### Linux - **AppImage**: Download, unzip, and run. -- **Arch Linux**: Install from AUR: +- **Arch Linux**: Install from AUR: + ```bash sudo pacman -Syu yay -S idescriptor-git ``` + make sure to do "sudo pacman -Syu" otherwise it's not going to find libimobiledevice>=1.4.0
@@ -93,7 +102,7 @@ make sure to do "sudo pacman -Syu" otherwise it's not going to find libimobilede | Feature | Status | Notes | | --------------------------- | -------------------- | --------------------------------------------- | | USB Connection | ✅ Implemented | Fully supported on Windows, macOS, and Linux. | -| Wireless Connection (Wi‑Fi) | ⚠️ To be implemented | - | +| Wireless Connection (Wi‑Fi) | ⚠️ Under development | - | ### Tools @@ -224,9 +233,9 @@ You might get this pop-up on any platform this is because this app uses secure b ## Become a Sponsor -Please support us at - AppImage - +Please support us at +AppImage + ## Thanks diff --git a/lib/idevice-rs b/lib/idevice-rs new file mode 160000 index 0000000..5f1e039 --- /dev/null +++ b/lib/idevice-rs @@ -0,0 +1 @@ +Subproject commit 5f1e03911f0819ceacd366f76f961be407bec2b6 diff --git a/src/afcexplorerwidget.cpp b/src/afcexplorerwidget.cpp index df98b72..b979996 100644 --- a/src/afcexplorerwidget.cpp +++ b/src/afcexplorerwidget.cpp @@ -43,8 +43,6 @@ #include #include #include -#include -#include AfcExplorerWidget::AfcExplorerWidget(iDescriptorDevice *device, bool favEnabled, afc_client_t afcClient, QString root, diff --git a/src/afcexplorerwidget.h b/src/afcexplorerwidget.h index 7c0e8e9..7c7362e 100644 --- a/src/afcexplorerwidget.h +++ b/src/afcexplorerwidget.h @@ -37,7 +37,6 @@ #include #include #include -#include class ExportManager; class ExportProgressDialog; @@ -89,7 +88,7 @@ private: ZIconWidget *m_enterButton; iDescriptorDevice *m_device; bool m_favEnabled; - afc_client_t m_afc; + AfcClientHandle *m_afc; QString m_errorMessage; QString m_root; diff --git a/src/appcontext.cpp b/src/appcontext.cpp index e7b9ab6..25b71b7 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -18,9 +18,11 @@ */ #include "appcontext.h" +#include "devicemonitor.h" #include "iDescriptor.h" #include "mainwindow.h" -#include "settingsmanager.h" +// #include "settingsmanager.h" +#include "networkdevicemanager.h" #include #include #include @@ -37,64 +39,191 @@ AppContext *AppContext::sharedInstance() and does not reconnect them until the user plugs them back in, even if they are still connected */ -AppContext::AppContext(QObject *parent) : QObject{parent} {} +AppContext::AppContext(QObject *parent) : QObject{parent} +{ -void AppContext::addDevice(QString udid, idevice_connection_type conn_type, - AddType addType) + // FIXME: windows and macOS support later + QDir lockdowndir("/var/lib/lockdown"); + 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) { + plist_t fileData = nullptr; + plist_read_from_file( + lockdowndir.filePath(fileName).toUtf8().constData(), &fileData, + NULL); + + if (!fileData) { + continue; + } + plist_print(fileData); + const std::string wifiMacAddress = + PlistNavigator(fileData)["WiFiMACAddress"].getString(); + plist_free(fileData); + qDebug() << "Found pairing file for MAC" + << QString::fromStdString(wifiMacAddress); + bool isCompatible = !wifiMacAddress.empty(); + // TODO: !important invalidate old pairing files + // libimobiledevice does not append WIFIMACAddress to the pairing file + if (!isCompatible) { + continue; + } + + IdevicePairingFile *pairing_file = nullptr; + idevice_pairing_file_read( + lockdowndir.filePath(fileName).toUtf8().constData(), &pairing_file); + if (pairing_file) { + qDebug() << "Caching pairing file for MAC" + << QString::fromStdString(wifiMacAddress); + m_pairingFileCache[QString::fromStdString(wifiMacAddress)] = + pairing_file; + } + } +} + +void AppContext::addDevice(QString udid, + DeviceMonitorThread::IdeviceConnectionType conn_type, + AddType addType, QString wifiMacAddress) { try { - iDescriptorInitDeviceResult initResult = - init_idescriptor_device(udid.toStdString().c_str()); + iDescriptorInitDeviceResult initResult; + + if (addType == AddType::UpgradeToWireless) { + const IdevicePairingFile *pairingFile = getCachedPairingFile(udid); + if (!pairingFile) { + qDebug() << "Cannot upgrade to wireless, no pairing file for" + << udid; + return; + } + + QList networkDevices = + NetworkDeviceManager::sharedInstance() + ->m_networkProvider->getNetworkDevices(); + + auto it = std::find_if( + networkDevices.constBegin(), networkDevices.constEnd(), + [wifiMacAddress](const NetworkDevice &device) { + return device.macAddress.compare(wifiMacAddress, + Qt::CaseInsensitive) == 0; + }); + + if (it != networkDevices.constEnd()) { + + IdevicePairingFile *pairing_file = nullptr; + idevice_pairing_file_read(QString("/var/lib/lockdown/%1.plist") + .arg(udid) + .toUtf8() + .constData(), + &pairing_file); + initResult = + init_idescriptor_device(udid, {it->address, pairing_file}); + } else { + qDebug() << "No network device found with MAC address:" + << wifiMacAddress; + return; + } + } else if (addType == AddType::Wireless) { + // FIXME: its not udid here its macAddress + const IdevicePairingFile *pairingFile = getCachedPairingFile(udid); + if (!pairingFile) { + qDebug() + << "Cannot initialize wireless device, no pairing file for" + << udid; + return; + } + + QList networkDevices = + NetworkDeviceManager::sharedInstance() + ->m_networkProvider->getNetworkDevices(); + + auto it = std::find_if( + networkDevices.constBegin(), networkDevices.constEnd(), + [wifiMacAddress](const NetworkDevice &device) { + return device.macAddress.compare(wifiMacAddress, + Qt::CaseInsensitive) == 0; + }); + + if (it != networkDevices.constEnd()) { + initResult = + init_idescriptor_device(udid, {it->address, pairingFile}); + } else { + qDebug() << "No network device found with MAC address:" + << wifiMacAddress; + return; + } + } + + else { + + initResult = init_idescriptor_device(udid, {nullptr, nullptr}); + } qDebug() << "init_idescriptor_device success ?: " << initResult.success; - qDebug() << "init_idescriptor_device error code: " << initResult.error; - + // qDebug() << "init_idescriptor_device error code: " << + // initResult.error; if (!initResult.success) { qDebug() << "Failed to initialize device with UDID: " << udid; - if (initResult.error == LOCKDOWN_E_PASSWORD_PROTECTED) { - if (addType == AddType::Regular) { - m_pendingDevices.append(udid); - emit devicePasswordProtected(udid); - emit deviceChange(); - QTimer::singleShot( - SettingsManager::sharedInstance()->connectionTimeout() * - 1000, - this, [this, udid]() { - if (m_pendingDevices.contains(udid)) { - qDebug() << "Pairing expired for device UDID: " - << udid; - m_pendingDevices.removeAll(udid); - emit devicePairingExpired(udid); - emit deviceChange(); - } - }); - } - } else if (initResult.error == - LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING || - initResult.error == LOCKDOWN_E_INVALID_HOST_ID) { - m_pendingDevices.append(udid); - emit devicePairPending(udid); - emit deviceChange(); - QTimer::singleShot( - SettingsManager::sharedInstance()->connectionTimeout() * - 1000, - this, [this, udid]() { - qDebug() - << "Pairing timer fired for device UDID: " << udid; - if (m_pendingDevices.contains(udid)) { - qDebug() - << "Pairing expired for device UDID: " << udid; - m_pendingDevices.removeAll(udid); - emit devicePairingExpired(udid); - emit deviceChange(); - } - }); - } else { - qDebug() << "Unhandled error for device UDID: " << udid - << " Error code: " << initResult.error; - } return; } + // if (!initResult.success) { + // qDebug() << "Failed to initialize device with UDID: " << + // udid; if (initResult.error == LOCKDOWN_E_PASSWORD_PROTECTED) + // { + // if (addType == AddType::Regular) { + // m_pendingDevices.append(udid); + // emit devicePasswordProtected(udid); + // emit deviceChange(); + // QTimer::singleShot( + // SettingsManager::sharedInstance()->connectionTimeout() + // * + // 1000, + // this, [this, udid]() { + // if (m_pendingDevices.contains(udid)) { + // qDebug() << "Pairing expired for device + // UDID: + // " + // << udid; + // m_pendingDevices.removeAll(udid); + // emit devicePairingExpired(udid); + // emit deviceChange(); + // } + // }); + // } + // } else if (initResult.error == + // LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING || + // initResult.error == LOCKDOWN_E_INVALID_HOST_ID) { + // m_pendingDevices.append(udid); + // emit devicePairPending(udid); + // emit deviceChange(); + // QTimer::singleShot( + // SettingsManager::sharedInstance()->connectionTimeout() + // * + // 1000, + // this, [this, udid]() { + // qDebug() + // << "Pairing timer fired for device UDID: " << + // udid; + // if (m_pendingDevices.contains(udid)) { + // qDebug() + // << "Pairing expired for device UDID: " << + // udid; + // m_pendingDevices.removeAll(udid); + // emit devicePairingExpired(udid); + // emit deviceChange(); + // } + // }); + // } else { + // qDebug() << "Unhandled error for device UDID: " << udid + // << " Error code: " << initResult.error; + // } + // return; + // } qDebug() << "Device initialized: " << udid; iDescriptorDevice *device = new iDescriptorDevice{ @@ -104,17 +233,20 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, .deviceInfo = initResult.deviceInfo, .afcClient = initResult.afcClient, .afc2Client = initResult.afc2Client, + .lockdown = initResult.lockdown, .mutex = new std::recursive_mutex(), }; m_devices[device->udid] = device; if (addType == AddType::Regular) { - SettingsManager::sharedInstance()->doIfEnabled( - SettingsManager::Setting::AutoRaiseWindow, []() { - if (MainWindow *mainWindow = MainWindow::sharedInstance()) { - mainWindow->raise(); - mainWindow->activateWindow(); - } - }); + qDebug() << "Regular device added: " << udid; + // SettingsManager::sharedInstance()->doIfEnabled( + // SettingsManager::Setting::AutoRaiseWindow, []() { + // if (MainWindow *mainWindow = + // MainWindow::sharedInstance()) { + // mainWindow->raise(); + // mainWindow->activateWindow(); + // } + // }); emit deviceAdded(device); emit deviceChange(); @@ -123,7 +255,6 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, emit devicePaired(device); emit deviceChange(); m_pendingDevices.removeAll(udid); - } catch (const std::exception &e) { qDebug() << "Exception in onDeviceAdded: " << e.what(); } @@ -131,19 +262,19 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, int AppContext::getConnectedDeviceCount() const { -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - return m_devices.size() + m_recoveryDevices.size(); -#else + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // return m_devices.size() + m_recoveryDevices.size(); + // #else return m_devices.size(); -#endif + // #endif } /* FIXME: on macOS, sometimes you get wireless disconnects even though we are not - listening for wireless devices it does not have any to do with us, but it - still happens so be aware of that -*/ + listening for wireless devices it does not have any to do with us, but + it still happens so be aware of that + */ void AppContext::removeDevice(QString _udid) { const std::string udid = _udid.toStdString(); @@ -169,41 +300,41 @@ void AppContext::removeDevice(QString _udid) iDescriptorDevice *device = m_devices[udid]; m_devices.remove(udid); - emit deviceRemoved(udid); + emit deviceRemoved(udid, device->deviceInfo.wifiMacAddress); emit deviceChange(); - std::lock_guard lock(*device->mutex); + // std::lock_guard lock(*device->mutex); - if (device->afcClient) - afc_client_free(device->afcClient); - if (device->afc2Client) - afc_client_free(device->afc2Client); - idevice_free(device->device); - delete device->mutex; - delete device; + // if (device->afcClient) + // afc_client_free(device->afcClient); + // if (device->afc2Client) + // afc_client_free(device->afc2Client); + // idevice_free(device->device); + // delete device->mutex; + // delete device; } #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT void AppContext::removeRecoveryDevice(uint64_t ecid) { - if (!m_recoveryDevices.contains(ecid)) { - qDebug() << "Device with ECID " + QString::number(ecid) + - " not found. Please report this issue."; - return; - } + // if (!m_recoveryDevices.contains(ecid)) { + // qDebug() << "Device with ECID " + QString::number(ecid) + + // " not found. Please report this issue."; + // return; + // } - qDebug() << "Removing recovery device with ECID:" << ecid; + // qDebug() << "Removing recovery device with ECID:" << ecid; - // Fix use-after-free: get pointer before removing from map - iDescriptorRecoveryDevice *deviceInfo = m_recoveryDevices.value(ecid); - m_recoveryDevices.remove(ecid); + // // Fix use-after-free: get pointer before removing from map + // iDescriptorRecoveryDevice *deviceInfo = + // m_recoveryDevices.value(ecid); m_recoveryDevices.remove(ecid); - emit recoveryDeviceRemoved(ecid); - emit deviceChange(); + // emit recoveryDeviceRemoved(ecid); + // emit deviceChange(); - std::lock_guard lock(*deviceInfo->mutex); - delete deviceInfo->mutex; - delete deviceInfo; + // std::lock_guard lock(*deviceInfo->mutex); + // delete deviceInfo->mutex; + // delete deviceInfo; } #endif @@ -217,91 +348,121 @@ QList AppContext::getAllDevices() return m_devices.values(); } -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -QList AppContext::getAllRecoveryDevices() -{ - return m_recoveryDevices.values(); -} -#endif +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// QList AppContext::getAllRecoveryDevices() +// { +// // return m_recoveryDevices.values(); +// } +// #endif // Returns whether there are any devices connected (regular or recovery) bool AppContext::noDevicesConnected() const { -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - return (m_devices.isEmpty() && m_recoveryDevices.isEmpty() && - m_pendingDevices.isEmpty()); -#else + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // return (m_devices.isEmpty() && m_recoveryDevices.isEmpty() && + // m_pendingDevices.isEmpty()); + // #else return (m_devices.isEmpty() && m_pendingDevices.isEmpty()); -#endif + // #endif } #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT void AppContext::addRecoveryDevice(uint64_t ecid) { - iDescriptorInitDeviceResultRecovery res = - init_idescriptor_recovery_device(ecid); + // iDescriptorInitDeviceResultRecovery res = + // init_idescriptor_recovery_device(ecid); - if (!res.success) { - qDebug() << "Failed to initialize recovery device with ECID: " - << QString::number(ecid); - qDebug() << "Error code: " << res.error; - return; - } + // if (!res.success) { + // qDebug() << "Failed to initialize recovery device with ECID: " + // << QString::number(ecid); + // qDebug() << "Error code: " << res.error; + // return; + // } - iDescriptorRecoveryDevice *recoveryDevice = new iDescriptorRecoveryDevice(); - recoveryDevice->ecid = res.deviceInfo.ecid; - recoveryDevice->mode = res.mode; - recoveryDevice->cpid = res.deviceInfo.cpid; - recoveryDevice->bdid = res.deviceInfo.bdid; - recoveryDevice->displayName = res.displayName; - recoveryDevice->mutex = new std::recursive_mutex(); + // iDescriptorRecoveryDevice *recoveryDevice = new + // iDescriptorRecoveryDevice(); recoveryDevice->ecid = + // res.deviceInfo.ecid; recoveryDevice->mode = res.mode; + // recoveryDevice->cpid = res.deviceInfo.cpid; + // recoveryDevice->bdid = res.deviceInfo.bdid; + // recoveryDevice->displayName = res.displayName; + // recoveryDevice->mutex = new std::recursive_mutex(); - m_recoveryDevices[res.deviceInfo.ecid] = recoveryDevice; - emit recoveryDeviceAdded(recoveryDevice); - emit deviceChange(); + // m_recoveryDevices[res.deviceInfo.ecid] = recoveryDevice; + // emit recoveryDeviceAdded(recoveryDevice); + // emit deviceChange(); } #endif AppContext::~AppContext() { - for (auto device : m_devices) { - emit deviceRemoved(device->udid); - if (device->afcClient) - afc_client_free(device->afcClient); - if (device->afc2Client) - afc_client_free(device->afc2Client); - idevice_free(device->device); - delete device->mutex; - delete device; - } + // for (auto device : m_devices) { + // emit deviceRemoved(device->udid); + // if (device->afcClient) + // afc_client_free(device->afcClient); + // if (device->afc2Client) + // afc_client_free(device->afc2Client); + // idevice_free(device->device); + // delete device->mutex; + // delete device; + // } -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - for (auto recoveryDevice : m_recoveryDevices) { - emit recoveryDeviceRemoved(recoveryDevice->ecid); - delete recoveryDevice->mutex; - delete recoveryDevice; - } -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // for (auto recoveryDevice : m_recoveryDevices) { + // emit recoveryDeviceRemoved(recoveryDevice->ecid); + // delete recoveryDevice->mutex; + // delete recoveryDevice; + // } + // #endif } void AppContext::setCurrentDeviceSelection(const DeviceSelection &selection) { - qDebug() << "New selection -" - << " Type:" << selection.type - << " UDID:" << QString::fromStdString(selection.udid) - << " ECID:" << selection.ecid << " Section:" << selection.section; - if (m_currentSelection.type == selection.type && - m_currentSelection.udid == selection.udid && - m_currentSelection.ecid == selection.ecid && - m_currentSelection.section == selection.section) { - qDebug() << "setCurrentDeviceSelection: No change in selection"; - return; // No change - } - m_currentSelection = selection; - emit currentDeviceSelectionChanged(m_currentSelection); + // qDebug() << "New selection -" + // << " Type:" << selection.type + // << " UDID:" << QString::fromStdString(selection.udid) + // << " ECID:" << selection.ecid << " Section:" << + // selection.section; + // if (m_currentSelection.type == selection.type && + // m_currentSelection.udid == selection.udid && + // m_currentSelection.ecid == selection.ecid && + // m_currentSelection.section == selection.section) { + // qDebug() << "setCurrentDeviceSelection: No change in selection"; + // return; // No change + // } + // m_currentSelection = selection; + // emit currentDeviceSelectionChanged(m_currentSelection); } const DeviceSelection &AppContext::getCurrentDeviceSelection() const { return m_currentSelection; -} \ No newline at end of file +} + +const iDescriptorDevice * +AppContext::getDeviceByMacAddress(const QString &macAddress) const +{ + for (const iDescriptorDevice *device : m_devices) { + if (device->deviceInfo.wifiMacAddress == macAddress.toStdString()) { + return device; + } + } + return nullptr; +} + +void AppContext::cachePairingFile(const QString &udid, + IdevicePairingFile *pairingFile) +{ + m_pairingFileCache.insert(udid, pairingFile); +} +const IdevicePairingFile * +AppContext::getCachedPairingFile(const QString &udid) const +{ + const IdevicePairingFile *pairingFile = nullptr; + + // Retrieve the pairing file from the cache + if (m_pairingFileCache.contains(udid)) { + pairingFile = m_pairingFileCache.value(udid); + } + + return pairingFile; +} diff --git a/src/appcontext.h b/src/appcontext.h index 3ba8c26..c4d5200 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -20,6 +20,7 @@ #ifndef APPCONTEXT_H #define APPCONTEXT_H +#include "devicemonitor.h" #include "devicesidebarwidget.h" #include "iDescriptor.h" #include @@ -33,32 +34,38 @@ public: QList getAllDevices(); explicit AppContext(QObject *parent = nullptr); bool noDevicesConnected() const; + void cachePairingFile(const QString &udid, IdevicePairingFile *pairingFile); + const IdevicePairingFile *getCachedPairingFile(const QString &udid) const; -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - QList getAllRecoveryDevices(); -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // QList getAllRecoveryDevices(); + // #endif ~AppContext(); int getConnectedDeviceCount() const; void setCurrentDeviceSelection(const DeviceSelection &selection); const DeviceSelection &getCurrentDeviceSelection() const; + const iDescriptorDevice * + getDeviceByMacAddress(const QString &macAddress) const; private: QMap m_devices; -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - QMap m_recoveryDevices; -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // QMap m_recoveryDevices; + // #endif QStringList m_pendingDevices; DeviceSelection m_currentSelection = DeviceSelection(""); + // FIXME: QString can be macAddress or udid - both works fine for now + QMap m_pairingFileCache; signals: void deviceAdded(iDescriptorDevice *device); - void deviceRemoved(const std::string &udid); + void deviceRemoved(const std::string &udid, const std::string &macAddress); void devicePaired(iDescriptorDevice *device); void devicePasswordProtected(const QString &udid); -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - void recoveryDeviceAdded(const iDescriptorRecoveryDevice *deviceInfo); - void recoveryDeviceRemoved(uint64_t ecid); -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // void recoveryDeviceAdded(const iDescriptorRecoveryDevice + // *deviceInfo); void recoveryDeviceRemoved(uint64_t ecid); + // #endif void devicePairPending(const QString &udid); void devicePairingExpired(const QString &udid); void systemSleepStarting(); @@ -74,8 +81,9 @@ signals: void currentDeviceSelectionChanged(const DeviceSelection &selection); public slots: void removeDevice(QString udid); - void addDevice(QString udid, idevice_connection_type connType, - AddType addType); + void addDevice(QString udid, + DeviceMonitorThread::IdeviceConnectionType connType, + AddType addType, QString wifiMacAddress = QString()); #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT void addRecoveryDevice(uint64_t ecid); void removeRecoveryDevice(uint64_t ecid); diff --git a/src/core/services/avahi/avahi_service.cpp b/src/core/services/avahi/avahi_service.cpp index 585061a..dda167c 100644 --- a/src/core/services/avahi/avahi_service.cpp +++ b/src/core/services/avahi/avahi_service.cpp @@ -217,9 +217,10 @@ void AvahiService::resolveCallback( avahi_free(value); } } - + device.macAddress = device.name.split('@').first(); qDebug() << "Resolved Apple device:" << device.name << "at" - << device.address << ":" << device.port; + << device.address << ":" << device.port + << "MAC:" << device.macAddress; // Add to our list if not already present { diff --git a/src/core/services/detect_jailbroken.cpp b/src/core/services/detect_jailbroken.cpp index ff41ec9..10c9347 100644 --- a/src/core/services/detect_jailbroken.cpp +++ b/src/core/services/detect_jailbroken.cpp @@ -18,7 +18,7 @@ */ #include "../../iDescriptor.h" -#include + // char *possible_jailbreak_paths[] = { // "/Applications/Cydia.app", // "/Library/MobileSubstrate/MobileSubstrate.dylib", @@ -29,18 +29,15 @@ // }; #include -bool detect_jailbroken(afc_client_t afc) +bool detect_jailbroken(AfcClientHandle *afc) { char **dirs = NULL; - if (afc_read_directory(afc, (std::string(POSSIBLE_ROOT) + "bin").c_str(), - &dirs) == AFC_E_SUCCESS) { - // if we can loop through the directory, it means we have access to the - // file system - for (char **dir = dirs; *dir != nullptr; ++dir) { - afc_dictionary_free(dirs); - return true; - } + size_t count = 0; + bool res = false; + if (!afc_list_directory(afc, (std::string(POSSIBLE_ROOT) + "bin").c_str(), + &dirs, &count)) { + free(dirs); } - afc_dictionary_free(dirs); - return false; + + return res > 0; } \ No newline at end of file diff --git a/src/core/services/get-device-info.cpp b/src/core/services/get-device-info.cpp index 2337a35..7c0a029 100644 --- a/src/core/services/get-device-info.cpp +++ b/src/core/services/get-device-info.cpp @@ -52,8 +52,8 @@ #include #endif -#include -#include +#include "../../iDescriptor.h" +#include #include #include @@ -82,35 +82,41 @@ static const char *domains[] = { "com.apple.mobile.iTunes", "com.apple.fmip", "com.apple.Accessibility", NULL}; -plist_t get_device_info(const char *udid, lockdownd_client_t client, - idevice_t device) +plist_t get_device_info(const char *udid, LockdowndClientHandle *client) { - lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; - idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; + IdeviceFfiError *err; plist_t node = NULL; /* run query and output information */ - if (lockdownd_get_value(client, NULL, NULL, &node) != LOCKDOWN_E_SUCCESS) { - fprintf(stderr, "ERROR: Could not get value\n"); + err = lockdownd_get_value(client, NULL, NULL, &node); + + if (err) { + qDebug() << "ERROR: Could not get value"; } plist_t disk_info = nullptr; uint64_t total_space = 0; uint64_t free_space = 0; - if (lockdownd_get_value(client, "com.apple.disk_usage", nullptr, - &disk_info) == LOCKDOWN_E_SUCCESS) { + err = lockdownd_get_value(client, nullptr, "com.apple.disk_usage", + &disk_info); + qDebug() << "Disk usage fetch error:" << (err ? err->message : "none"); + + if (!err) { + qDebug() << "Disk Usage Info:"; + plist_print(disk_info); + // merge dict plist_dict_merge(&node, disk_info); - plist_free(disk_info); + // plist_free(disk_info); } return node; } -void get_device_info_xml(const char *udid, lockdownd_client_t client, - idevice_t device, pugi::xml_document &infoXml) +void get_device_info_xml(const char *udid, LockdowndClientHandle *client, + pugi::xml_document &infoXml) { - plist_t node = get_device_info(udid, client, device); + plist_t node = get_device_info(udid, client); if (!node) return; char *xml_string = nullptr; diff --git a/src/core/services/get_battery_info.cpp b/src/core/services/get_battery_info.cpp index 65cd169..18ab2e5 100644 --- a/src/core/services/get_battery_info.cpp +++ b/src/core/services/get_battery_info.cpp @@ -20,35 +20,45 @@ #include "../../iDescriptor.h" #include "plist/plist.h" #include -#include #include -void get_battery_info(std::string productType, idevice_t idevice, - bool is_iphone, plist_t &diagnostics) +// FIXME: return bool +void get_battery_info(IdeviceProviderHandle *provider, plist_t &diagnostics) { - diagnostics_relay_client_t diagnostics_client = nullptr; - try { + // 1. Connect to the diagnostics_relay service using the raw C function. + DiagnosticsRelayClientHandle *client_handle = nullptr; + IdeviceFfiError *err = + ::diagnostics_relay_client_connect(provider, &client_handle); - if (diagnostics_relay_client_start_service(idevice, &diagnostics_client, - nullptr) != - DIAGNOSTICS_RELAY_E_SUCCESS) { - qDebug() << "Failed to start diagnostics relay service."; - return; - } + if (err) { + qDebug() << "Failed to create diagnostics relay client:" + << err->message; + idevice_error_free(err); + return; + } - if (diagnostics_relay_query_ioregistry_entry( - diagnostics_client, nullptr, "IOPMPowerSource", &diagnostics) != - DIAGNOSTICS_RELAY_E_SUCCESS && - !diagnostics) { + // 2. Adopt the raw handle into the C++ RAII wrapper. + // The client will now be automatically freed when it goes out of scope. + auto diagnostics_client = + IdeviceFFI::DiagnosticsRelay::adopt(client_handle); - qDebug() - << "Failed to query diagnostics relay for AppleARMPMUCharger."; - if (diagnostics_client) - diagnostics_relay_client_free(diagnostics_client); - } - } catch (const std::exception &e) { - if (diagnostics_client) - diagnostics_relay_client_free(diagnostics_client); - qDebug() << "Exception in get_battery_info: " << e.what(); + // 3. Query IORegistry for battery info. + auto ioreg_result = diagnostics_client.ioregistry( + IdeviceFFI::None, // current_plane + IdeviceFFI::None, // entry_name + IdeviceFFI::Some(std::string("IOPMPowerSource")) // entry_class + ); + + if (!ioreg_result.is_ok()) { + qDebug() << "Failed to query IORegistry:" + << ioreg_result.unwrap_err().message.c_str(); + return; + } + + // 4. Unwrap the result and handle the optional plist. + auto plist_opt = std::move(ioreg_result).unwrap(); + if (plist_opt.is_some()) { + // The caller of get_battery_info is responsible for freeing this plist. + diagnostics = std::move(plist_opt).unwrap(); } } \ No newline at end of file diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp index 0062a21..8ef71bc 100644 --- a/src/core/services/init_device.cpp +++ b/src/core/services/init_device.cpp @@ -19,16 +19,19 @@ #include "../../devicedatabase.h" #include "../../iDescriptor.h" -#include "../../servicemanager.h" +// #include "../../servicemanager.h" +#include "../../appcontext.h" #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT #include "libirecovery.h" #endif #include -#include -#include -#include #include +#include +#include +#include + +#include std::string safeGetXML(const char *key, pugi::xml_node dict) { for (pugi::xml_node child = dict.first_child(); child; @@ -150,7 +153,8 @@ void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d) } DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, - afc_client_t &afcClient, + AfcClientHandle *afcClient, + IdeviceProviderHandle *provider, iDescriptorInitDeviceResult &result) { pugi::xml_node dict = doc.child("plist").child("dict"); @@ -194,6 +198,7 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, d.bluetoothAddress = safeGet("BluetoothAddress"); d.firmwareVersion = safeGet("FirmwareVersion"); d.productVersion = safeGet("ProductVersion"); + d.wifiMacAddress = safeGet("WiFiAddress"); QString q_version = QString::fromStdString(d.productVersion); QStringList parts = q_version.split('.'); @@ -206,17 +211,25 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, /*DiskInfo*/ try { - d.diskInfo.totalDiskCapacity = - std::stoull(safeGet("TotalDiskCapacity")); - d.diskInfo.totalDataCapacity = - std::stoull(safeGet("TotalDataCapacity")); - d.diskInfo.totalSystemCapacity = - std::stoull(safeGet("TotalSystemCapacity")); + auto safeParseU64 = [&](const char *key) -> uint64_t { + std::string s = safeGet(key); + if (s.empty()) + return 0; + try { + return std::stoull(s); + } catch (...) { + qDebug() << "Failed to parse key to uint64_t:" << key + << "value:" << QString::fromStdString(s); + return 0; + } + }; + d.diskInfo.totalDiskCapacity = safeParseU64("TotalDiskCapacity"); + d.diskInfo.totalDataCapacity = safeParseU64("TotalDataCapacity"); + d.diskInfo.totalSystemCapacity = safeParseU64("TotalSystemCapacity"); /* For some reason this is way inaccrutate for iOS 17 and up */ - d.diskInfo.totalDataAvailable = - std::stoull(safeGet("TotalDataAvailable")); + d.diskInfo.totalDataAvailable = safeParseU64("TotalDataAvailable"); try { /* @@ -226,13 +239,19 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, // "FSTotalBytes: 63966400512" // "FSFreeBytes: 2867101696" // "FSBlockSize: 4096" - char **info = NULL; - afc_get_device_info(afcClient, &info); - if (info && info[6]) { - d.diskInfo.totalDataAvailable = - std::stoull(std::string(info[5])); + AfcDeviceInfo *info = new AfcDeviceInfo(); + IdeviceFfiError *err = afc_get_device_info(afcClient, info); + if (err) { + qDebug() << "AFC get device info error code: " << err->message; + return d; } - afc_dictionary_free(info); + if (info) { + + qDebug() << "AFC Disk Info" << info->free_bytes; + d.diskInfo.totalDataAvailable = info->free_bytes; + } + // FIXME: free + afc_device_info_free(info); } catch (const std::exception &e) { qDebug() << "Error parsing disk info: " << e.what(); } @@ -281,14 +300,14 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, /*BatteryInfo*/ plist_t diagnostics = nullptr; - get_battery_info(rawProductType, result.device, d.is_iPhone, diagnostics); + get_battery_info(provider, diagnostics); if (!diagnostics) { qDebug() << "Failed to get diagnostics plist."; return d; } try { - PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"]; + PlistNavigator ioreg = PlistNavigator(diagnostics); // old devices do not have "BatteryData" d.oldDevice = !ioreg["BatteryData"]; @@ -329,6 +348,7 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, d.batteryInfo.serialNumber = !batterySerialNumber.empty() ? batterySerialNumber : "Error retrieving serial number"; + qDebug() << "Cycle count: " << cycleCount; parseDeviceBattery(ioreg, d); plist_free(diagnostics); diagnostics = nullptr; @@ -340,156 +360,289 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, } } -iDescriptorInitDeviceResult init_idescriptor_device(const char *udid) +// [DeviceMonitor] Device connected: "a5c08c1dfdc9fcf81366bd6159c81bba73deaa27" +// Device added: "a5c08c1dfdc9fcf81366bd6159c81bba73deaa27" +// Initializing iDescriptor device with UDID: +// "a5c08c1dfdc9fcf81366bd6159c81bba73deaa27" Failed to create idevice handle +// Initialization failed, cleaning up resources. FfiInvalidArg +// init_idescriptor_device success ?: false +// Failed to initialize device with UDID: +// "a5c08c1dfdc9fcf81366bd6159c81bba73deaa27" +iDescriptorInitDeviceResult +init_idescriptor_device(const QString &udid, WirelessInitArgs wirelessArgs) { - qDebug() << "Initializing iDescriptor device with UDID: " - << QString::fromUtf8(udid); + const bool isWireless = + !wirelessArgs.ip.isEmpty() && wirelessArgs.pairing_file; + qDebug() << "Initializing iDescriptor device with UDID: " << udid + << (isWireless ? "over wireless" : "over USB"); + iDescriptorInitDeviceResult result = {}; - // 1. Initialize all resource handles to nullptr - idevice_t device = nullptr; - lockdownd_client_t client = nullptr; - lockdownd_service_descriptor_t lockdownService = nullptr; - afc_client_t afcClient = nullptr; - afc_client_t afc2Client = nullptr; + UsbmuxdConnectionHandle *usbmuxd_conn = nullptr; + UsbmuxdAddrHandle *addr_handle = nullptr; + IdeviceProviderHandle *provider = nullptr; + LockdowndClientHandle *lockdown = nullptr; + IdeviceSocketHandle *socket = nullptr; + AfcClientHandle *afc_client = nullptr; + AfcClientHandle *afc2_client = nullptr; pugi::xml_document infoXml; + uint32_t actual_device_id = 0; + IdevicePairingFile *pairing_file = nullptr; + IdeviceHandle *deviceHandle = nullptr; + // FIXME: remove debug + std::stringstream ss; - idevice_error_t ret = - idevice_new_with_options(&device, udid, IDEVICE_LOOKUP_USBMUX); + // 1. Connect to usbmuxd + IdeviceFfiError *err = + idevice_usbmuxd_new_default_connection(0, &usbmuxd_conn); + if (err) { + if (!isWireless) { + qDebug() << "Failed to connect to usbmuxd"; + goto cleanup; + } + } - if (ret != IDEVICE_E_SUCCESS) { - qDebug() << "Failed to connect to device: " << ret; - // result.error is not set here as idevice_error_t is different + // 2. Create default address handle + err = idevice_usbmuxd_default_addr_new(&addr_handle); + if (err) { + qDebug() << "Failed to create address handle"; goto cleanup; } - lockdownd_error_t ldret; - if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake( - device, &client, APP_LABEL))) { - result.error = ldret; - qDebug() << "Failed to create lockdown client: " << ldret; - goto cleanup; - } - - if (LOCKDOWN_E_SUCCESS != - (ldret = lockdownd_start_service(client, "com.apple.afc", - &lockdownService))) { - result.error = ldret; - qDebug() << "Failed to start AFC service: " << ldret; - goto cleanup; - } - - if (afc_client_new(device, lockdownService, &afcClient) != AFC_E_SUCCESS) { - qDebug() << "Failed to create AFC client."; - - goto cleanup; - } - - // AFC2 is optional, so we don't goto cleanup on failure - afc_error_t afc2_err; - if ((afc2_err = afc2_client_new(device, &afc2Client)) != AFC_E_SUCCESS) { - qDebug() << "AFC2 client not available. Error:" << afc2_err; - afc2Client = nullptr; + if (isWireless) { + // Create IPv4 sockaddr + struct sockaddr_in addr_in; + memset(&addr_in, 0, sizeof(addr_in)); + addr_in.sin_family = AF_INET; + addr_in.sin_port = htons(0); // Port doesn't matter for provider + inet_pton(AF_INET, wirelessArgs.ip.toUtf8().constData(), + &addr_in.sin_addr); + // IdevicePairingFile *pairing_file = nullptr; + // idevice_pairing_file_read( + // wirelessArgs.pairing_file.toUtf8().constData(), &pairing_file); + err = idevice_tcp_provider_new( + (const idevice_sockaddr *)&addr_in, + const_cast(wirelessArgs.pairing_file), + APP_LABEL, &provider); + if (err) { + qDebug() << "Failed to create wireless provider"; + goto cleanup; + } + // err = heartbeat_new(); + // heartbeat_connect } else { - qDebug() << "AFC2 client created successfully."; + + UsbmuxdDeviceHandle **devices; + int device_count; + err = + idevice_usbmuxd_get_devices(usbmuxd_conn, &devices, &device_count); + + // Find by UDID and get its device_id + for (size_t i = 0; i < device_count; i++) { + const char *device_udid = + idevice_usbmuxd_device_get_udid(devices[i]); + if (strcmp(device_udid, udid.toUtf8().constData()) == 0) { + actual_device_id = + idevice_usbmuxd_device_get_device_id(devices[i]); + break; + } + } + + // 3. Create provider for the device (actual function name) + err = usbmuxd_provider_new(addr_handle, 0, udid.toUtf8().constData(), + actual_device_id, APP_LABEL, &provider); } - get_device_info_xml(udid, client, device, infoXml); - - if (infoXml.empty()) { - qDebug() << "Failed to retrieve device info XML for UDID: " - << QString::fromUtf8(udid); + if (err) { + qDebug() << "Failed to create provider"; goto cleanup; } - // If we got this far, the core initialization is successful + // 4. Connect to lockdown (actual function name) + err = lockdownd_connect(provider, &lockdown); + if (err) { + qDebug() << "Failed to connect to lockdown"; + goto cleanup; + } + // err = idevice_new(socket, "iDescriptor", &deviceHandle); + // if (err) { + // qDebug() << "Failed to create idevice handle"; + // goto cleanup; + // } + + err = idevice_provider_get_pairing_file(provider, &pairing_file); + if (err) { + qDebug() << "Failed to get pairing file"; + goto cleanup; + } + + err = lockdownd_start_session(lockdown, pairing_file); + if (err) { + qDebug() << "Failed to start lockdown session"; + goto cleanup; + } + + uint16_t heartbeat_port; + bool heartbeat_ssl; + if (isWireless) { + // err = lockdownd_start_service(lockdown, "com.apple.heartbeat", + // &heartbeat_port, &heartbeat_ssl); + // if (err) { + // qDebug() << "Failed to start Heartbeat service"; + // goto cleanup; + // } + + // Start heartbeat client to keep connection alive + HeartbeatClientHandle *heartbeat = nullptr; + err = heartbeat_connect(provider, &heartbeat); + + if (err) { + qDebug() << "Failed to connect to Heartbeat client"; + goto cleanup; + } + + // // After getting the heartbeat port from lockdown + // IdeviceHandle *deviceHandle = nullptr; + + // // Then create IdeviceHandle from the socket + // err = idevice_new(socket, "heartbeat", &deviceHandle); + // if (err) { + // qDebug() << "Failed to create idevice handle"; + // goto cleanup; + // } + + // // Now use with heartbeat_new + // HeartbeatClientHandle *heartbeat = nullptr; + // err = heartbeat_new(deviceHandle, &heartbeat); + // if (err) { + // qDebug() << "Failed to create Heartbeat client"; + // goto cleanup; + // } + + qDebug() << "Heartbeat client created successfully"; + } + + // 5. Start AFC service + uint16_t afc_port; + bool afc_ssl; + err = + lockdownd_start_service(lockdown, "com.apple.afc", &afc_port, &afc_ssl); + if (err) { + qDebug() << "Failed to start AFC service"; + goto cleanup; + } + + // 6. Create AFC client from provider + err = afc_client_connect(provider, &afc_client); + if (err) { + qDebug() << "Failed to create AFC client"; + goto cleanup; + } + + // 7. AFC2 is optional + uint16_t afc2_port; + bool afc2_ssl; + err = lockdownd_start_service(lockdown, "com.apple.afc2", &afc2_port, + &afc2_ssl); + if (!err) { + err = afc_client_connect(provider, &afc2_client); + } + + get_device_info_xml(udid.toUtf8().constData(), lockdown, infoXml); + infoXml.print(ss, " "); // " " for indentation + qDebug().noquote() << "--- Full Device Info XML ---" + << QString::fromStdString(ss.str()); + + result.device = provider; result.success = true; - result.device = device; - result.afcClient = afcClient; - result.afc2Client = afc2Client; - fullDeviceInfo(infoXml, afcClient, result); + result.afcClient = afc_client; + result.afc2Client = afc2_client; + result.lockdown = lockdown; + AppContext::sharedInstance()->cachePairingFile(udid, pairing_file); + fullDeviceInfo(infoXml, afc_client, provider, result); cleanup: - if (lockdownService) { - lockdownd_service_descriptor_free(lockdownService); - } - if (client) { - lockdownd_client_free(client); - } - - // free on error + // Cleanup on error + // FIXME: implement proper cleanup + // one of them causes a crash here, needs investigation if (!result.success) { - if (afc2Client) { - afc_client_free(afc2Client); - } - if (afcClient) { - afc_client_free(afcClient); - } - if (device) { - idevice_free(device); - } + qDebug() << "Initialization failed, cleaning up resources." + << err->message; + // if (afc2_client) + // afc_client_free(afc2_client); + // if (afc_client) + // afc_client_free(afc_client); + // if (lockdown) + // lockdownd_client_free(lockdown); + // if (provider) + // idevice_provider_free(provider); + // if (addr_handle) + // idevice_usbmuxd_addr_free(addr_handle); + // if (usbmuxd_conn) + // idevice_usbmuxd_connection_free(usbmuxd_conn); } return result; } -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -iDescriptorInitDeviceResultRecovery -init_idescriptor_recovery_device(uint64_t ecid) -{ - qDebug() << "Initializing iDescriptor recovery device with ECID: " << ecid; - iDescriptorInitDeviceResultRecovery result = {}; - irecv_client_t client = nullptr; - const irecv_device_info *deviceInfo = nullptr; - irecv_device_t device = nullptr; - const DeviceDatabaseInfo *info = nullptr; +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// iDescriptorInitDeviceResultRecovery +// init_idescriptor_recovery_device(uint64_t ecid) +// { +// qDebug() << "Initializing iDescriptor recovery device with ECID: " << +// ecid; iDescriptorInitDeviceResultRecovery result = {}; - irecv_error_t ret = irecv_open_with_ecid_and_attempts( - &client, ecid, RECOVERY_CLIENT_CONNECTION_TRIES); +// irecv_client_t client = nullptr; +// const irecv_device_info *deviceInfo = nullptr; +// irecv_device_t device = nullptr; +// const DeviceDatabaseInfo *info = nullptr; - if (ret != IRECV_E_SUCCESS) { - qDebug() << "Failed to open recovery client with ECID:" << ecid - << "Error:" << ret; - result.error = ret; - goto cleanup; - } +// irecv_error_t ret = irecv_open_with_ecid_and_attempts( +// &client, ecid, RECOVERY_CLIENT_CONNECTION_TRIES); - ret = irecv_get_mode(client, (int *)&result.mode); - if (ret != IRECV_E_SUCCESS) { - qDebug() << "Failed to get recovery mode. Error:" << ret; - result.error = ret; - goto cleanup; - } +// if (ret != IRECV_E_SUCCESS) { +// qDebug() << "Failed to open recovery client with ECID:" << ecid +// << "Error:" << ret; +// result.error = ret; +// goto cleanup; +// } - deviceInfo = irecv_get_device_info(client); - if (!deviceInfo) { - qDebug() << "Failed to get device info from recovery client"; - result.error = IRECV_E_UNKNOWN_ERROR; - goto cleanup; - } +// ret = irecv_get_mode(client, (int *)&result.mode); +// if (ret != IRECV_E_SUCCESS) { +// qDebug() << "Failed to get recovery mode. Error:" << ret; +// result.error = ret; +// goto cleanup; +// } - if (irecv_devices_get_device_by_client(client, &device) == - IRECV_E_SUCCESS && - device && device->hardware_model) { - qDebug() << "Recovery device hardware_model: " - << device->hardware_model; - info = - DeviceDatabase::findByHwModel(std::string(device->hardware_model)); - } else { - qDebug() << "Could not resolve hardware_model from client."; - } +// deviceInfo = irecv_get_device_info(client); +// if (!deviceInfo) { +// qDebug() << "Failed to get device info from recovery client"; +// result.error = IRECV_E_UNKNOWN_ERROR; +// goto cleanup; +// } - result.displayName = - info ? (info->displayName ? info->displayName : info->marketingName) - : "Unknown Device"; - result.deviceInfo = *deviceInfo; - result.success = true; +// if (irecv_devices_get_device_by_client(client, &device) == +// IRECV_E_SUCCESS && +// device && device->hardware_model) { +// qDebug() << "Recovery device hardware_model: " +// << device->hardware_model; +// info = +// DeviceDatabase::findByHwModel(std::string(device->hardware_model)); +// } else { +// qDebug() << "Could not resolve hardware_model from client."; +// } -cleanup: - if (client) { - irecv_close(client); - } +// result.displayName = +// info ? (info->displayName ? info->displayName : info->marketingName) +// : "Unknown Device"; +// result.deviceInfo = *deviceInfo; +// result.success = true; - return result; -} -#endif // ENABLE_RECOVERY_DEVICE_SUPPORT \ No newline at end of file +// cleanup: +// if (client) { +// irecv_close(client); +// } + +// return result; +// } +// #endif // ENABLE_RECOVERY_DEVICE_SUPPORT \ No newline at end of file diff --git a/src/deviceimagewidget.cpp b/src/deviceimagewidget.cpp index 6723686..8b361ef 100644 --- a/src/deviceimagewidget.cpp +++ b/src/deviceimagewidget.cpp @@ -18,13 +18,13 @@ */ #include "deviceimagewidget.h" +#include "iDescriptor.h" #include #include #include #include #include #include -#include DeviceImageWidget::DeviceImageWidget(iDescriptorDevice *device, QWidget *parent) : QWidget(parent), m_device(device) @@ -161,7 +161,7 @@ QString DeviceImageWidget::getMockupNameFromDisplayName( int DeviceImageWidget::getIosVersionFromDevice() const { - unsigned int version = idevice_get_device_version(m_device->device); + unsigned int version = m_device->deviceInfo.parsedDeviceVersion; if (version > 0) { int majorVersion = (version >> 16) & 0xFF; @@ -180,7 +180,7 @@ int DeviceImageWidget::getIosVersionFromDevice() const } } - // If all else fails, return unknown version (will use ios26 wallpaper) + // return unknown version (will use ios26 wallpaper) return 0; } diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp index 7f02ea0..047f226 100644 --- a/src/deviceinfowidget.cpp +++ b/src/deviceinfowidget.cpp @@ -20,12 +20,12 @@ #include "deviceinfowidget.h" #include "batterywidget.h" #include "diskusagewidget.h" -#include "fileexplorerwidget.h" +// #include "fileexplorerwidget.h" #include "iDescriptor-ui.h" #include "iDescriptor.h" #include "infolabel.h" #include "privateinfolabel.h" -#include "toolboxwidget.h" +// #include "toolboxwidget.h" #include #include #include @@ -78,20 +78,20 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) QIcon(":/resources/icons/IcOutlinePowerSettingsNew.png"), "Shutdown", this); shutdownBtn->setIconSize(QSize(20, 20)); - connect(shutdownBtn, &ZIconWidget::clicked, this, - [device]() { ToolboxWidget::shutdownDevice(device); }); + // connect(shutdownBtn, &ZIconWidget::clicked, this, + // [device]() { ToolboxWidget::shutdownDevice(device); }); ZIconWidget *restartBtn = new ZIconWidget( QIcon(":/resources/icons/IcTwotoneRestartAlt.png"), "Restart", this); restartBtn->setIconSize(QSize(20, 20)); - connect(restartBtn, &ZIconWidget::clicked, this, - [device]() { ToolboxWidget::restartDevice(device); }); + // connect(restartBtn, &ZIconWidget::clicked, this, + // [device]() { ToolboxWidget::restartDevice(device); }); ZIconWidget *recoveryBtn = new ZIconWidget( QIcon(":/resources/icons/HugeiconsWrench01.png"), "Recovery", this); recoveryBtn->setIconSize(QSize(20, 20)); - connect(recoveryBtn, &ZIconWidget::clicked, this, - [device]() { ToolboxWidget::_enterRecoveryMode(device); }); + // connect(recoveryBtn, &ZIconWidget::clicked, this, + // [device]() { ToolboxWidget::_enterRecoveryMode(device); }); actionsLayout->addWidget(shutdownBtn); actionsLayout->addWidget(restartBtn); @@ -259,25 +259,27 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) infoItems.append( {"Hardware Platform:", createValueLabel(QString::fromStdString( device->deviceInfo.hardwarePlatform))}); - infoItems.append( - {"Battery Cycle:", createValueLabel(QString::number( - m_device->deviceInfo.batteryInfo.cycleCount))}); + // infoItems.append( + // {"Battery Cycle:", createValueLabel(QString::number( + // m_device->deviceInfo.batteryInfo.cycleCount))}); infoItems.append( {"Firmware Version:", createValueLabel(QString::fromStdString( device->deviceInfo.firmwareVersion))}); - // Battery Info - QWidget *batteryWidget = new QWidget(); - QHBoxLayout *batteryLayout = new QHBoxLayout(batteryWidget); - batteryLayout->setContentsMargins(0, 0, 0, 0); - batteryLayout->setSpacing(5); - batteryLayout->addWidget(new QLabel(device->deviceInfo.batteryInfo.health)); - QPushButton *moreButton = new QPushButton("More"); - connect(moreButton, &QPushButton::clicked, this, - &DeviceInfoWidget::onBatteryMoreClicked); - batteryLayout->addWidget(moreButton); - batteryLayout->addStretch(); - infoItems.append({"Battery Health:", batteryWidget}); + // // FIXME: Battery Info + // // QWidget *batteryWidget = new QWidget(); + // // QHBoxLayout *batteryLayout = new QHBoxLayout(batteryWidget); + // // batteryLayout->setContentsMargins(0, 0, 0, 0); + // // batteryLayout->setSpacing(5); + // // batteryLayout->addWidget(new + // // QLabel(device->deviceInfo.batteryInfo.health)); QPushButton + // *moreButton = + // // new QPushButton("More"); connect(moreButton, &QPushButton::clicked, + // this, + // // &DeviceInfoWidget::onBatteryMoreClicked); + // // batteryLayout->addWidget(moreButton); + // // batteryLayout->addStretch(); + // // infoItems.append({"Battery Health:", batteryWidget}); infoItems.append( {"Production Device:", @@ -322,7 +324,7 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) } infoLayout->addWidget(gridContainer); - // infoLayout->addStretch(); // Pushes footer to the bottom + infoLayout->addStretch(); // Pushes footer to the bottom // Footer QLabel *footerLabel = @@ -341,16 +343,16 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) rightSideLayout->addWidget(new DiskUsageWidget(device, this)); rightSideLayout->addStretch(); - // TODO: layout shift cause ? - // rightSideLayout->setAlignment(Qt::AlignCenter); + // // TODO: layout shift cause ? + // // rightSideLayout->setAlignment(Qt::AlignCenter); mainLayout->addLayout(rightSideLayout); mainLayout->addStretch(); - m_updateTimer = new QTimer(this); - connect(m_updateTimer, &QTimer::timeout, this, - &DeviceInfoWidget::updateBatteryInfo); - m_updateTimer->start(30000); // Update every 30 seconds + // m_updateTimer = new QTimer(this); + // connect(m_updateTimer, &QTimer::timeout, this, + // &DeviceInfoWidget::updateBatteryInfo); + // m_updateTimer->start(30000); // Update every 30 seconds } DeviceInfoWidget::~DeviceInfoWidget() {} @@ -370,47 +372,47 @@ void DeviceInfoWidget::onBatteryMoreClicked() void DeviceInfoWidget::updateBatteryInfo() { - qDebug() << "Updating battery info..."; - plist_t diagnostics = nullptr; - get_battery_info(m_device->deviceInfo.rawProductType, m_device->device, - m_device->deviceInfo.is_iPhone, diagnostics); + // qDebug() << "Updating battery info..."; + // plist_t diagnostics = nullptr; + // get_battery_info(m_device->deviceInfo.rawProductType, m_device->device, + // m_device->deviceInfo.is_iPhone, diagnostics); - if (!diagnostics) { - qDebug() << "Failed to get diagnostics plist."; - return; - } - /*DATA*/ - DeviceInfo &d = m_device->deviceInfo; - qDebug() << "old device" << d.oldDevice; - PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"]; - if (d.oldDevice) - parseOldDeviceBattery(ioreg, d); - else - parseDeviceBattery(ioreg, d); - /*UI*/ - updateChargingStatusIcon(); - m_chargingWattsWithCableTypeLabel->setText( - QString::number(d.batteryInfo.watts) + "W" + "/" + - (d.batteryInfo.usbConnectionType == BatteryInfo::ConnectionType::USB - ? "USB" - : "USB-C")); + // if (!diagnostics) { + // qDebug() << "Failed to get diagnostics plist."; + // return; + // } + // /*DATA*/ + // DeviceInfo &d = m_device->deviceInfo; + // qDebug() << "old device" << d.oldDevice; + // PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"]; + // // if (d.oldDevice) + // // parseOldDeviceBattery(ioreg, d); + // // else + // // parseDeviceBattery(ioreg, d); + // /*UI*/ + // updateChargingStatusIcon(); + // m_chargingWattsWithCableTypeLabel->setText( + // QString::number(d.batteryInfo.watts) + "W" + "/" + + // (d.batteryInfo.usbConnectionType == BatteryInfo::ConnectionType::USB + // ? "USB" + // : "USB-C")); - m_batteryWidget->updateContext( - d.batteryInfo.isCharging, - qBound(1, d.batteryInfo.currentBatteryLevel, 100)); + // m_batteryWidget->updateContext( + // d.batteryInfo.isCharging, + // qBound(1, d.batteryInfo.currentBatteryLevel, 100)); } void DeviceInfoWidget::updateChargingStatusIcon() { - if (m_device->deviceInfo.batteryInfo.isCharging) { - m_chargingStatusLabel->setText("Charging"); - m_chargingStatusLabel->setStyleSheet( - QString("color: %1;").arg(COLOR_GREEN.name())); - m_lightningIconLabel->show(); + // if (m_device->deviceInfo.batteryInfo.isCharging) { + // m_chargingStatusLabel->setText("Charging"); + // m_chargingStatusLabel->setStyleSheet( + // QString("color: %1;").arg(COLOR_GREEN.name())); + // m_lightningIconLabel->show(); - } else { - m_chargingStatusLabel->setText("Not Charging"); - m_chargingStatusLabel->setStyleSheet(""); - m_lightningIconLabel->hide(); - } + // } else { + // m_chargingStatusLabel->setText("Not Charging"); + // m_chargingStatusLabel->setStyleSheet(""); + // m_lightningIconLabel->hide(); + // } } \ No newline at end of file diff --git a/src/devicemanagerwidget.cpp b/src/devicemanagerwidget.cpp index 508f209..9a9accd 100644 --- a/src/devicemanagerwidget.cpp +++ b/src/devicemanagerwidget.cpp @@ -20,10 +20,10 @@ #include "devicemanagerwidget.h" #include "appcontext.h" #include "devicemenuwidget.h" -#include "devicependingwidget.h" -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -#include "recoverydeviceinfowidget.h" -#endif +// #include "devicependingwidget.h" +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// #include "recoverydeviceinfowidget.h" +// #endif #include "settingsmanager.h" #include @@ -37,12 +37,12 @@ DeviceManagerWidget::DeviceManagerWidget(QWidget *parent) addDevice(device); // Apply settings-based behavior for switching to new device - SettingsManager::sharedInstance()->doIfEnabled( - SettingsManager::Setting::SwitchToNewDevice, - [this, device]() { - AppContext::sharedInstance()->setCurrentDeviceSelection( - DeviceSelection(device->udid)); - }); + // SettingsManager::sharedInstance()->doIfEnabled( + // SettingsManager::Setting::SwitchToNewDevice, + // [this, device]() { + // AppContext::sharedInstance()->setCurrentDeviceSelection( + // DeviceSelection(device->udid)); + // }); emit updateNoDevicesConnected(); }); @@ -72,29 +72,32 @@ DeviceManagerWidget::DeviceManagerWidget(QWidget *parent) connect(AppContext::sharedInstance(), &AppContext::devicePaired, this, [this](iDescriptorDevice *device) { addPairedDevice(device); - SettingsManager::sharedInstance()->doIfEnabled( - SettingsManager::Setting::SwitchToNewDevice, - [this, device]() { - AppContext::sharedInstance()->setCurrentDeviceSelection( - DeviceSelection(device->udid)); - }); + // SettingsManager::sharedInstance()->doIfEnabled( + // SettingsManager::Setting::SwitchToNewDevice, + // [this, device]() { + // AppContext::sharedInstance()->setCurrentDeviceSelection( + // DeviceSelection(device->udid)); + // }); emit updateNoDevicesConnected(); }); -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - connect(AppContext::sharedInstance(), &AppContext::recoveryDeviceAdded, - this, [this](const iDescriptorRecoveryDevice *recoveryDeviceInfo) { - addRecoveryDevice(recoveryDeviceInfo); - emit updateNoDevicesConnected(); - }); + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // connect(AppContext::sharedInstance(), + // &AppContext::recoveryDeviceAdded, + // this, [this](const iDescriptorRecoveryDevice + // *recoveryDeviceInfo) { + // addRecoveryDevice(recoveryDeviceInfo); + // emit updateNoDevicesConnected(); + // }); - connect(AppContext::sharedInstance(), &AppContext::recoveryDeviceRemoved, - this, [this](uint64_t ecid) { - removeRecoveryDevice(ecid); - emit updateNoDevicesConnected(); - }); -#endif + // connect(AppContext::sharedInstance(), + // &AppContext::recoveryDeviceRemoved, + // this, [this](uint64_t ecid) { + // removeRecoveryDevice(ecid); + // emit updateNoDevicesConnected(); + // }); + // #endif connect(AppContext::sharedInstance(), &AppContext::devicePairingExpired, this, [this](const QString &udid) { @@ -146,94 +149,97 @@ void DeviceManagerWidget::addDevice(iDescriptorDevice *device) std::pair{deviceWidget, m_sidebar->addDevice(tabTitle, device->udid)}; } -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -void DeviceManagerWidget::addRecoveryDevice( - const iDescriptorRecoveryDevice *device) -{ - try { - // Create device info widget - RecoveryDeviceInfoWidget *recoveryDeviceInfoWidget = - new RecoveryDeviceInfoWidget(device); - m_recoveryDeviceWidgets.insert( - device->ecid, - std::pair{recoveryDeviceInfoWidget, - m_sidebar->addRecoveryDevice(device->ecid)}); - m_stackedWidget->addWidget(recoveryDeviceInfoWidget); +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// void DeviceManagerWidget::addRecoveryDevice( +// const iDescriptorRecoveryDevice *device) +// { +// try { +// // Create device info widget +// RecoveryDeviceInfoWidget *recoveryDeviceInfoWidget = +// new RecoveryDeviceInfoWidget(device); +// m_recoveryDeviceWidgets.insert( +// device->ecid, +// std::pair{recoveryDeviceInfoWidget, +// m_sidebar->addRecoveryDevice(device->ecid)}); +// m_stackedWidget->addWidget(recoveryDeviceInfoWidget); - } catch (...) { - qDebug() << "Error initializing recovery device"; - } -} +// } catch (...) { +// qDebug() << "Error initializing recovery device"; +// } +// } -void DeviceManagerWidget::removeRecoveryDevice(uint64_t ecid) -{ - qDebug() << "Removing recovery device with ECID:" << ecid; - if (!m_recoveryDeviceWidgets.contains(ecid)) { - qDebug() << "Recovery device with ECID" + QString::number(ecid) + - " not found. Please report this issue."; - return; - } +// void DeviceManagerWidget::removeRecoveryDevice(uint64_t ecid) +// { +// qDebug() << "Removing recovery device with ECID:" << ecid; +// if (!m_recoveryDeviceWidgets.contains(ecid)) { +// qDebug() << "Recovery device with ECID" + QString::number(ecid) + +// " not found. Please report this issue."; +// return; +// } - RecoveryDeviceInfoWidget *deviceWidget = - m_recoveryDeviceWidgets[ecid].first; - RecoveryDeviceSidebarItem *sidebarItem = - m_recoveryDeviceWidgets[ecid].second; +// RecoveryDeviceInfoWidget *deviceWidget = +// m_recoveryDeviceWidgets[ecid].first; +// RecoveryDeviceSidebarItem *sidebarItem = +// m_recoveryDeviceWidgets[ecid].second; - if (deviceWidget != nullptr && sidebarItem != nullptr) { - qDebug() << "Recovery device exists removing:" << QString::number(ecid); +// if (deviceWidget != nullptr && sidebarItem != nullptr) { +// qDebug() << "Recovery device exists removing:" << +// QString::number(ecid); - m_recoveryDeviceWidgets.remove(ecid); - m_stackedWidget->removeWidget(deviceWidget); - m_sidebar->removeRecoveryDevice(ecid); - deviceWidget->deleteLater(); +// m_recoveryDeviceWidgets.remove(ecid); +// m_stackedWidget->removeWidget(deviceWidget); +// m_sidebar->removeRecoveryDevice(ecid); +// deviceWidget->deleteLater(); - emit updateNoDevicesConnected(); - } -} -#endif +// emit updateNoDevicesConnected(); +// } +// } +// #endif void DeviceManagerWidget::addPendingDevice(const QString &udid, bool locked) { - qDebug() << "Adding pending device:" << udid; - if (m_pendingDeviceWidgets.contains(udid.toStdString()) && !locked) { - qDebug() << "Pending device already exists, moving to next state:" - << udid; - m_pendingDeviceWidgets[udid.toStdString()].first->next(); - return; - } else if (m_pendingDeviceWidgets.contains(udid.toStdString()) && locked) { - // Already exists and still locked, do nothing - qDebug() - << "Pending device already exists and is locked, doing nothing:" - << udid; - return; - } + // qDebug() << "Adding pending device:" << udid; + // if (m_pendingDeviceWidgets.contains(udid.toStdString()) && !locked) { + // qDebug() << "Pending device already exists, moving to next state:" + // << udid; + // m_pendingDeviceWidgets[udid.toStdString()].first->next(); + // return; + // } else if (m_pendingDeviceWidgets.contains(udid.toStdString()) && locked) + // { + // // Already exists and still locked, do nothing + // qDebug() + // << "Pending device already exists and is locked, doing nothing:" + // << udid; + // return; + // } - qDebug() << "Created pending widget for:" << udid << "Locked:" << locked; - DevicePendingWidget *pendingWidget = new DevicePendingWidget(locked, this); - m_stackedWidget->addWidget(pendingWidget); - m_pendingDeviceWidgets[udid.toStdString()] = - std::pair{pendingWidget, m_sidebar->addPendingDevice(udid)}; + // qDebug() << "Created pending widget for:" << udid << "Locked:" << locked; + // DevicePendingWidget *pendingWidget = new DevicePendingWidget(locked, + // this); m_stackedWidget->addWidget(pendingWidget); + // m_pendingDeviceWidgets[udid.toStdString()] = + // std::pair{pendingWidget, m_sidebar->addPendingDevice(udid)}; } void DeviceManagerWidget::removePendingDevice(const QString &udid) { - qDebug() << "Removing pending device:" << udid; - if (!m_pendingDeviceWidgets.contains(udid.toStdString())) { - qDebug() << "Pending device not found:" << udid; - return; - } - std::string udidStr = udid.toStdString(); - DevicePendingWidget *deviceWidget = m_pendingDeviceWidgets[udidStr].first; - DevicePendingSidebarItem *sidebarItem = - m_pendingDeviceWidgets[udidStr].second; + // qDebug() << "Removing pending device:" << udid; + // if (!m_pendingDeviceWidgets.contains(udid.toStdString())) { + // qDebug() << "Pending device not found:" << udid; + // return; + // } + // std::string udidStr = udid.toStdString(); + // DevicePendingWidget *deviceWidget = + // m_pendingDeviceWidgets[udidStr].first; DevicePendingSidebarItem + // *sidebarItem = + // m_pendingDeviceWidgets[udidStr].second; - if (deviceWidget != nullptr && sidebarItem != nullptr) { - qDebug() << "Pending device exists removing:" << udid; - m_pendingDeviceWidgets.remove(udidStr); - m_stackedWidget->removeWidget(deviceWidget); - m_sidebar->removePendingDevice(udidStr); - deviceWidget->deleteLater(); - } + // if (deviceWidget != nullptr && sidebarItem != nullptr) { + // qDebug() << "Pending device exists removing:" << udid; + // m_pendingDeviceWidgets.remove(udidStr); + // m_stackedWidget->removeWidget(deviceWidget); + // m_sidebar->removePendingDevice(udidStr); + // deviceWidget->deleteLater(); + // } } void DeviceManagerWidget::addPairedDevice(iDescriptorDevice *device) @@ -335,18 +341,19 @@ void DeviceManagerWidget::onDeviceSelectionChanged( } break; -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - case DeviceSelection::Recovery: - if (m_recoveryDeviceWidgets.contains(selection.ecid)) { - QWidget *tabWidget = m_recoveryDeviceWidgets[selection.ecid].first; - if (tabWidget) { - m_stackedWidget->setCurrentWidget(tabWidget); - // Clear current device since we're viewing recovery device - m_currentDeviceUuid = ""; - } - } - break; -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // case DeviceSelection::Recovery: + // if (m_recoveryDeviceWidgets.contains(selection.ecid)) { + // QWidget *tabWidget = + // m_recoveryDeviceWidgets[selection.ecid].first; if + // (tabWidget) { + // m_stackedWidget->setCurrentWidget(tabWidget); + // // Clear current device since we're viewing recovery + // device m_currentDeviceUuid = ""; + // } + // } + // break; + // #endif case DeviceSelection::Pending: if (m_pendingDeviceWidgets.contains(selection.udid)) { diff --git a/src/devicemanagerwidget.h b/src/devicemanagerwidget.h index 8f9f574..deb8a83 100644 --- a/src/devicemanagerwidget.h +++ b/src/devicemanagerwidget.h @@ -24,9 +24,9 @@ #include "devicependingwidget.h" #include "devicesidebarwidget.h" #include "iDescriptor.h" -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -#include "recoverydeviceinfowidget.h" -#endif +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// #include "recoverydeviceinfowidget.h" +// #endif #include #include #include @@ -53,10 +53,10 @@ private: void addDevice(iDescriptorDevice *device); void removeDevice(const std::string &uuid); -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - void addRecoveryDevice(const iDescriptorRecoveryDevice *device); - void removeRecoveryDevice(uint64_t ecid); -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // void addRecoveryDevice(const iDescriptorRecoveryDevice *device); + // void removeRecoveryDevice(uint64_t ecid); + // #endif void addPendingDevice(const QString &udid, bool locked); void addPairedDevice(iDescriptorDevice *device); void removePendingDevice(const QString &udid); @@ -72,11 +72,12 @@ private: std::pair> m_pendingDeviceWidgets; // Map to store devices by UDID -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - QMap> - m_recoveryDeviceWidgets; // Map to store recovery devices by ECID -#endif + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // QMap> + // m_recoveryDeviceWidgets; // Map to store recovery devices by ECID + // #endif std::string m_currentDeviceUuid; }; diff --git a/src/devicemenuwidget.cpp b/src/devicemenuwidget.cpp index aa051b9..def6524 100644 --- a/src/devicemenuwidget.cpp +++ b/src/devicemenuwidget.cpp @@ -55,30 +55,30 @@ void DeviceMenuWidget::init() // Create and add widgets to the stacked widget m_deviceInfoWidget = new DeviceInfoWidget(device, this); - m_installedAppsWidget = new InstalledAppsWidget(device, this); - m_galleryWidget = new GalleryWidget(device, this); - m_fileExplorerWidget = new FileExplorerWidget(device, this); + // m_installedAppsWidget = new InstalledAppsWidget(device, this); + // m_galleryWidget = new GalleryWidget(device, this); + // m_fileExplorerWidget = new FileExplorerWidget(device, this); // Set minimum heights - m_galleryWidget->setMinimumHeight(300); - m_fileExplorerWidget->setMinimumHeight(300); + // m_galleryWidget->setMinimumHeight(300); + // m_fileExplorerWidget->setMinimumHeight(300); - stackedWidget->addWidget(m_deviceInfoWidget); // Index 0 - Info - stackedWidget->addWidget(m_installedAppsWidget); // Index 1 - Apps - stackedWidget->addWidget(m_galleryWidget); // Index 2 - Gallery - stackedWidget->addWidget(m_fileExplorerWidget); // Index 3 - Files + stackedWidget->addWidget(m_deviceInfoWidget); // Index 0 - Info + // stackedWidget->addWidget(m_installedAppsWidget); // Index 1 - Apps + // stackedWidget->addWidget(m_galleryWidget); // Index 2 - Gallery + // stackedWidget->addWidget(m_fileExplorerWidget); // Index 3 - Files // Set default to Info tab stackedWidget->setCurrentWidget(m_deviceInfoWidget); // Connect to current changed signal for lazy loading - connect(stackedWidget, &QStackedWidget::currentChanged, this, - [this](int index) { - if (index == 2) { // Gallery tab - qDebug() << "Switched to Gallery tab"; - m_galleryWidget->load(); - } - }); + // connect(stackedWidget, &QStackedWidget::currentChanged, this, + // [this](int index) { + // if (index == 2) { // Gallery tab + // qDebug() << "Switched to Gallery tab"; + // m_galleryWidget->load(); + // } + // }); QWidget *loadingWidget = stackedWidget->widget(0); stackedWidget->removeWidget(loadingWidget); @@ -89,12 +89,12 @@ void DeviceMenuWidget::switchToTab(const QString &tabName) { if (tabName == "Info") { stackedWidget->setCurrentWidget(m_deviceInfoWidget); - } else if (tabName == "Apps") { - stackedWidget->setCurrentWidget(m_installedAppsWidget); - } else if (tabName == "Gallery") { - stackedWidget->setCurrentWidget(m_galleryWidget); + // } else if (tabName == "Apps") { + // stackedWidget->setCurrentWidget(m_installedAppsWidget); + // } else if (tabName == "Gallery") { + // stackedWidget->setCurrentWidget(m_galleryWidget); } else if (tabName == "Files") { - stackedWidget->setCurrentWidget(m_fileExplorerWidget); + // stackedWidget->setCurrentWidget(m_fileExplorerWidget); } else { qDebug() << "Tab not found:" << tabName; } diff --git a/src/devicemenuwidget.h b/src/devicemenuwidget.h index cf0480a..ea94647 100644 --- a/src/devicemenuwidget.h +++ b/src/devicemenuwidget.h @@ -20,10 +20,10 @@ #ifndef DEVICEMENUWIDGET_H #define DEVICEMENUWIDGET_H #include "deviceinfowidget.h" -#include "fileexplorerwidget.h" +// #include "fileexplorerwidget.h" #include "gallerywidget.h" #include "iDescriptor.h" -#include "installedappswidget.h" +// #include "installedappswidget.h" #include #include @@ -41,9 +41,9 @@ private: QStackedWidget *stackedWidget; // Pointer to the stacked widget iDescriptorDevice *device; // Pointer to the iDescriptor device DeviceInfoWidget *m_deviceInfoWidget; - InstalledAppsWidget *m_installedAppsWidget; - GalleryWidget *m_galleryWidget; - FileExplorerWidget *m_fileExplorerWidget; + // InstalledAppsWidget *m_installedAppsWidget; + // GalleryWidget *m_galleryWidget; + // FileExplorerWidget *m_fileExplorerWidget; signals: }; diff --git a/src/devicemonitor.h b/src/devicemonitor.h new file mode 100644 index 0000000..c2898aa --- /dev/null +++ b/src/devicemonitor.h @@ -0,0 +1,126 @@ +#ifndef DEVICEMONITOR_H +#define DEVICEMONITOR_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace IdeviceFFI; + +class DeviceMonitorThread : public QThread +{ + Q_OBJECT +public: + DeviceMonitorThread(QObject *parent = nullptr) : QThread(parent) {} + + void run() override + { + while (!isInterruptionRequested()) { + // Create connection + UsbmuxdConnectionHandle *usbmuxd_conn; + IdeviceFfiError *err = + idevice_usbmuxd_new_default_connection(0, &usbmuxd_conn); + if (err) { + idevice_error_free(err); + QThread::msleep(1000); // Wait before retry + continue; + } + + UsbmuxdListenerHandle *listener; + err = idevice_usbmuxd_listen(usbmuxd_conn, &listener); + if (err) { + idevice_usbmuxd_connection_free(usbmuxd_conn); + idevice_error_free(err); + QThread::msleep(1000); + continue; + } + + // Monitor loop + while (!isInterruptionRequested()) { + bool connect = false; + UsbmuxdDeviceHandle *device; + uint32_t disconnect_id; + + err = idevice_usbmuxd_listener_next(listener, &connect, &device, + &disconnect_id); + qDebug() << "Listening for device connections..." << err + << connect; + if (err) { + // Check if it's just the stream ending (no devices) + if (err->code == -1) { // Socket error code + qDebug() << "Listener stream ended, reconnecting..."; + idevice_error_free(err); + break; // Break inner loop to reconnect + } else { + qDebug() << "Real error:" << err->message; + idevice_error_free(err); + break; + } + } + + if (connect) { + const char *udid = idevice_usbmuxd_device_get_udid(device); + uint32_t device_id = + idevice_usbmuxd_device_get_device_id(device); + uint8_t conn_type = + idevice_usbmuxd_device_get_connection_type(device); + + // Skip network devices (same as original callback) + if (conn_type == CONNECTION_NETWORK) { + qDebug() << "Skipping network device:" << QString(udid); + idevice_usbmuxd_device_free(device); + continue; + } + + deviceMap[device_id] = QString(udid); + qDebug() + << "[DeviceMonitor] Device connected:" << QString(udid); + + emit deviceEvent(IDEVICE_DEVICE_ADD, QString(udid), + conn_type, AddType::Regular); + idevice_usbmuxd_device_free(device); + } else { + QString udid = deviceMap.value(disconnect_id, QString()); + if (!udid.isEmpty()) { + emit deviceEvent(IDEVICE_DEVICE_REMOVE, udid, + CONNECTION_USB, AddType::Regular); + deviceMap.remove(disconnect_id); + } else { + qDebug() << "Unknown device disconnected please report " + "this issue: " + << disconnect_id; + } + } + } + + // Cleanup before reconnecting + idevice_usbmuxd_listener_handle_free(listener); + idevice_usbmuxd_connection_free(usbmuxd_conn); + } + } + + enum IdeviceEventType { + IDEVICE_DEVICE_ADD = 1, + IDEVICE_DEVICE_REMOVE = 2, + IDEVICE_DEVICE_PAIRED = 3 + }; + + enum IdeviceConnectionType { CONNECTION_USB = 1, CONNECTION_NETWORK = 2 }; + + enum AddType { Regular = 0, Pairing = 1 }; + +signals: + void deviceEvent(int event, const QString &udid, int conn_type, + int addType); + +private: + QMap deviceMap; +}; +#endif // DEVICEMONITOR_H \ No newline at end of file diff --git a/src/diskusagewidget.cpp b/src/diskusagewidget.cpp index 64eea78..0561698 100644 --- a/src/diskusagewidget.cpp +++ b/src/diskusagewidget.cpp @@ -27,9 +27,9 @@ #include #include -#include -#include -#include +// #include +// #include +// #include DiskUsageWidget::DiskUsageWidget(iDescriptorDevice *device, QWidget *parent) : QWidget(parent), m_device(device), m_state(Loading), m_totalCapacity(0), @@ -95,31 +95,33 @@ void DiskUsageWidget::setupUI() m_diskBarLayout->setContentsMargins(0, 0, 0, 0); m_diskBarLayout->setSpacing(0); -/* - FIXME: There is bug with qt, related to NSPopover on macOS - need to revisit this when we find a fix -*/ -// #ifdef Q_OS_MAC -// m_systemBar = new DiskUsageBar(); -// m_appsBar = new DiskUsageBar(); -// m_mediaBar = new DiskUsageBar(); -// m_othersBar = new DiskUsageBar(); -// m_freeBar = new DiskUsageBar(); + /* + FIXME: There is bug with qt, related to NSPopover on macOS + need to revisit this when we find a fix + */ + // #ifdef Q_OS_MAC + // m_systemBar = new DiskUsageBar(); + // m_appsBar = new DiskUsageBar(); + // m_mediaBar = new DiskUsageBar(); + // m_othersBar = new DiskUsageBar(); + // m_freeBar = new DiskUsageBar(); -// m_systemBar->setStyleSheet( -// " background-color: #a1384d; border: 1px solid" -// "#e64a5b; padding: 0; margin: 0; border-top-left-radius: 3px; " -// "border-bottom-left-radius: 3px; "); -// m_appsBar->setStyleSheet("background-color: #4f869f; border: 1px solid " -// "#63b4da; padding: 0; margin: 0; "); -// m_mediaBar->setStyleSheet("background-color: #2ECC71; " -// "border: none; padding: 0; margin: 0; "); -// m_othersBar->setStyleSheet("background-color: #a28729; border: 1px solid " -// "#c4a32d; padding: 0; margin: 0; "); -// m_freeBar->setStyleSheet( -// "background-color: #6e6d6d; border: 1px solid " -// "#4f4f4f; padding: 0; margin: 0; border-top-right-radius: 3px; " -// "border-bottom-right-radius: 3px; "); + // m_systemBar->setStyleSheet( + // " background-color: #a1384d; border: 1px solid" + // "#e64a5b; padding: 0; margin: 0; border-top-left-radius: 3px; " + // "border-bottom-left-radius: 3px; "); + // m_appsBar->setStyleSheet("background-color: #4f869f; border: 1px + // solid " + // "#63b4da; padding: 0; margin: 0; "); + // m_mediaBar->setStyleSheet("background-color: #2ECC71; " + // "border: none; padding: 0; margin: 0; "); + // m_othersBar->setStyleSheet("background-color: #a28729; border: 1px + // solid " + // "#c4a32d; padding: 0; margin: 0; "); + // m_freeBar->setStyleSheet( + // "background-color: #6e6d6d; border: 1px solid " + // "#4f4f4f; padding: 0; margin: 0; border-top-right-radius: 3px; " + // "border-bottom-right-radius: 3px; "); m_systemBar = new QWidget(); m_appsBar = new QWidget(); @@ -221,6 +223,7 @@ void DiskUsageWidget::updateUI() if (m_totalCapacity == 0) { m_processIndicator->stop(); + m_processIndicator->hide(); m_statusLabel->setText("No disk information available."); m_stackedWidget->setCurrentWidget(m_loadingErrorPage); return; @@ -318,19 +321,22 @@ void DiskUsageWidget::updateUI() m_diskBarLayout->setStretchFactor(m_othersBar, othersStretch); m_diskBarLayout->setStretchFactor(m_freeBar, freeStretch); -/* FIXME: NSPopover bug */ + /* FIXME: NSPopover bug */ // #ifdef Q_OS_MAC -// m_systemBar->setUsageInfo("System", formatSize(m_systemUsage), "#a1384d", -// (double)m_systemUsage / m_totalCapacity); -// m_appsBar->setUsageInfo("Apps", formatSize(m_appsUsage), "#3498DB", -// (double)m_appsUsage / m_totalCapacity); -// m_mediaBar->setUsageInfo("Media", formatSize(m_mediaUsage), "#2ECC71", -// (double)m_mediaUsage / m_totalCapacity); -// m_othersBar->setUsageInfo("Others", formatSize(m_othersUsage), "#F39C12", -// (double)m_othersUsage / m_totalCapacity); -// m_freeBar->setUsageInfo("Free", formatSize(m_freeSpace), "#BDC3C7", -// (double)m_freeSpace / m_totalCapacity); -// #else + // m_systemBar->setUsageInfo("System", formatSize(m_systemUsage), + // "#a1384d", + // (double)m_systemUsage / m_totalCapacity); + // m_appsBar->setUsageInfo("Apps", formatSize(m_appsUsage), "#3498DB", + // (double)m_appsUsage / m_totalCapacity); + // m_mediaBar->setUsageInfo("Media", formatSize(m_mediaUsage), + // "#2ECC71", + // (double)m_mediaUsage / m_totalCapacity); + // m_othersBar->setUsageInfo("Others", formatSize(m_othersUsage), + // "#F39C12", + // (double)m_othersUsage / m_totalCapacity); + // m_freeBar->setUsageInfo("Free", formatSize(m_freeSpace), "#BDC3C7", + // (double)m_freeSpace / m_totalCapacity); + // #else m_systemBar->setToolTip( QString("System: %1 (%2%)") .arg(formatSize(m_systemUsage)) @@ -357,7 +363,6 @@ void DiskUsageWidget::updateUI() .arg(QString::number((double)m_freeSpace / m_totalCapacity * 100, 'f', 1))); - // Hide segments with zero usage // m_systemBar->setVisible(m_systemUsage > 0); // m_appsBar->setVisible(m_appsUsage > 0); @@ -365,7 +370,6 @@ void DiskUsageWidget::updateUI() // m_othersBar->setVisible(m_othersUsage > 0); // m_freeBar->setVisible(m_freeSpace > 0); } - void DiskUsageWidget::fetchData() { auto *watcher = new QFutureWatcher(this); @@ -376,6 +380,7 @@ void DiskUsageWidget::fetchData() m_state = Error; m_errorMessage = result["error"].toString(); } else { + qDebug() << "Disk usage data fetched:" << result; m_totalCapacity = result["totalCapacity"].toULongLong(); m_systemUsage = result["systemUsage"].toULongLong(); m_appsUsage = result["appsUsage"].toULongLong(); @@ -393,17 +398,18 @@ void DiskUsageWidget::fetchData() m_state = Ready; } - updateUI(); // Update the UI instead of triggering repaint + updateUI(); watcher->deleteLater(); }); - QFuture future = QtConcurrent::run([this]() { + QFuture future = QtConcurrent::run([this]() -> QVariantMap { QVariantMap result; if (!m_device || !m_device->device) { result["error"] = "Invalid device."; return result; } + // Pre-populate with known info result["totalCapacity"] = QVariant::fromValue( m_device->deviceInfo.diskInfo.totalDiskCapacity); result["freeSpace"] = QVariant::fromValue( @@ -411,41 +417,21 @@ void DiskUsageWidget::fetchData() result["systemUsage"] = QVariant::fromValue( m_device->deviceInfo.diskInfo.totalSystemCapacity); + // Create provider wrapper from existing handle + Provider provider = Provider::adopt(m_device->device); + // Apps usage uint64_t totalAppsSpace = 0; - instproxy_client_t instproxy = nullptr; - lockdownd_client_t lockdownClient = nullptr; - lockdownd_service_descriptor_t lockdowndService = nullptr; - - if (lockdownd_client_new_with_handshake(m_device->device, - &lockdownClient, APP_LABEL) != - LOCKDOWN_E_SUCCESS) { - result["error"] = "Could not connect to lockdown service."; + auto instproxy_res = IdeviceFFI::InstallationProxy::connect(provider); + if (instproxy_res.is_err()) { + result["error"] = + "Could not connect to installation proxy: " + + QString::fromStdString(instproxy_res.unwrap_err().message); return result; } + auto instproxy = std::move(instproxy_res.unwrap()); - if (lockdownd_start_service(lockdownClient, - "com.apple.mobile.installation_proxy", - &lockdowndService) != LOCKDOWN_E_SUCCESS) { - result["error"] = "Could not start installation proxy service."; - lockdownd_client_free(lockdownClient); - return result; - } - - if (instproxy_client_new(m_device->device, lockdowndService, - &instproxy) != INSTPROXY_E_SUCCESS) { - result["error"] = "Could not connect to installation proxy."; - lockdownd_service_descriptor_free(lockdowndService); - lockdownd_client_free(lockdownClient); - return result; - } - - // The service descriptor is no longer needed after the client is - // created - lockdownd_service_descriptor_free(lockdowndService); - lockdowndService = nullptr; - - plist_t client_opts = instproxy_client_options_new(); + plist_t client_opts = plist_new_dict(); plist_dict_set_item(client_opts, "ApplicationType", plist_new_string("User")); @@ -456,56 +442,51 @@ void DiskUsageWidget::fetchData() plist_new_string("DynamicDiskUsage")); plist_dict_set_item(client_opts, "ReturnAttributes", return_attrs); - plist_t apps = nullptr; - if (instproxy_browse(instproxy, client_opts, &apps) == - INSTPROXY_E_SUCCESS && - apps) { - if (plist_get_node_type(apps) == PLIST_ARRAY) { - for (uint32_t i = 0; i < plist_array_get_size(apps); i++) { - plist_t app_info = plist_array_get_item(apps, i); - if (!app_info) - continue; + auto apps_result = instproxy.browse(client_opts); + if (apps_result.is_ok()) { + auto apps = std::move(apps_result.unwrap()); + for (const auto &app_info : apps) { + plist_t static_usage = + plist_dict_get_item(app_info, "StaticDiskUsage"); + if (static_usage && + plist_get_node_type(static_usage) == PLIST_UINT) { + uint64_t static_size = 0; + plist_get_uint_val(static_usage, &static_size); + totalAppsSpace += static_size; + } - plist_t static_usage = - plist_dict_get_item(app_info, "StaticDiskUsage"); - if (static_usage && - plist_get_node_type(static_usage) == PLIST_UINT) { - uint64_t static_size = 0; - plist_get_uint_val(static_usage, &static_size); - totalAppsSpace += static_size; - } - - plist_t dynamic_usage = - plist_dict_get_item(app_info, "DynamicDiskUsage"); - if (dynamic_usage && - plist_get_node_type(dynamic_usage) == PLIST_UINT) { - uint64_t dynamic_size = 0; - plist_get_uint_val(dynamic_usage, &dynamic_size); - totalAppsSpace += dynamic_size; - } + plist_t dynamic_usage = + plist_dict_get_item(app_info, "DynamicDiskUsage"); + if (dynamic_usage && + plist_get_node_type(dynamic_usage) == PLIST_UINT) { + uint64_t dynamic_size = 0; + plist_get_uint_val(dynamic_usage, &dynamic_size); + totalAppsSpace += dynamic_size; } } - plist_free(apps); } result["appsUsage"] = QVariant::fromValue(totalAppsSpace); - plist_free(client_opts); - instproxy_client_free(instproxy); + plist_free(client_opts); // client_opts is consumed by browse, but // Media usage uint64_t mediaSpace = 0; - plist_t node = nullptr; - if (lockdownd_get_value(lockdownClient, "com.apple.mobile.iTunes", - nullptr, &node) == LOCKDOWN_E_SUCCESS && - node) { - plist_t mediaNode = plist_dict_get_item(node, "MediaLibrarySize"); - if (mediaNode && plist_get_node_type(mediaNode) == PLIST_UINT) { - plist_get_uint_val(mediaNode, &mediaSpace); + IdeviceFFI::Lockdown lockdown = + IdeviceFFI::Lockdown::adopt(m_device->lockdown); + auto itunes_info_res = + lockdown.get_value("com.apple.mobile.iTunes", nullptr); + if (itunes_info_res.is_ok()) { + auto itunes_dict = std::move(itunes_info_res.unwrap()); + if (itunes_dict) { + plist_t media_node = + plist_dict_get_item(itunes_dict, "MediaLibrarySize"); + if (media_node && + plist_get_node_type(media_node) == PLIST_UINT) { + plist_get_uint_val(media_node, &mediaSpace); + } } - plist_free(node); } result["mediaUsage"] = QVariant::fromValue(mediaSpace); - lockdownd_client_free(lockdownClient); return result; }); watcher->setFuture(future); diff --git a/src/fileexplorerwidget.cpp b/src/fileexplorerwidget.cpp index 32da91a..0b7c024 100644 --- a/src/fileexplorerwidget.cpp +++ b/src/fileexplorerwidget.cpp @@ -41,8 +41,6 @@ #include #include #include -#include -#include FileExplorerWidget::FileExplorerWidget(iDescriptorDevice *device, QWidget *parent) diff --git a/src/fileexplorerwidget.h b/src/fileexplorerwidget.h index a2eb418..7aa68d8 100644 --- a/src/fileexplorerwidget.h +++ b/src/fileexplorerwidget.h @@ -34,7 +34,6 @@ #include #include #include -#include class FileExplorerWidget : public QWidget { @@ -49,7 +48,7 @@ private slots: private: QSplitter *m_mainSplitter; QStackedWidget *m_stackedWidget; - afc_client_t currentAfcClient; + AfcClientHandle *currentAfcClient; QTreeWidget *m_sidebarTree; iDescriptorDevice *m_device; diff --git a/src/iDescriptor.h b/src/iDescriptor.h index defb1cf..cd89726 100644 --- a/src/iDescriptor.h +++ b/src/iDescriptor.h @@ -24,15 +24,20 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -#include -#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -54,8 +59,11 @@ "https://raw.githubusercontent.com/iDescriptor/iDescriptor/refs/heads/" \ "main/DeveloperDiskImages.json" -// This is because afc_read_directory accepts "/var/mobile/Media" as "/" +// This is because afc_list_directory accepts "/var/mobile/Media" as "/" #define POSSIBLE_ROOT "../../../../" +#define IDEVICE_DEVICE_VERSION(maj, min, patch) \ + ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF)) +#include "devicemonitor.h" struct BatteryInfo { QString health; @@ -172,59 +180,62 @@ struct DeviceInfo { std::string regionRaw; std::string region; unsigned int parsedDeviceVersion; + std::string wifiMacAddress; }; struct iDescriptorDevice { std::string udid; - idevice_connection_type conn_type; - idevice_t device; + DeviceMonitorThread::IdeviceConnectionType conn_type; + IdeviceProviderHandle *device; DeviceInfo deviceInfo; - afc_client_t afcClient; - afc_client_t afc2Client; + AfcClientHandle *afcClient; + AfcClientHandle *afc2Client; + LockdowndClientHandle *lockdown; bool is_iPhone; std::recursive_mutex *mutex; }; struct iDescriptorInitDeviceResult { bool success = false; - lockdownd_error_t error; - idevice_t device; + IdeviceFfiError error; + IdeviceProviderHandle *device; DeviceInfo deviceInfo; - afc_client_t afcClient; - afc_client_t afc2Client; + AfcClientHandle *afcClient; + AfcClientHandle *afc2Client; + LockdowndClientHandle *lockdown; }; -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -struct iDescriptorRecoveryDevice { - uint64_t ecid; - irecv_mode mode; - uint32_t cpid; - uint32_t bdid; - std::string displayName; - std::recursive_mutex *mutex; -}; -#endif +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// struct iDescriptorRecoveryDevice { +// uint64_t ecid; +// irecv_mode mode; +// uint32_t cpid; +// uint32_t bdid; +// std::string displayName; +// std::recursive_mutex *mutex; +// }; +// #endif struct TakeScreenshotResult { bool success = false; QImage img; }; -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -struct iDescriptorInitDeviceResultRecovery { - irecv_client_t client = nullptr; - irecv_device_info deviceInfo; - irecv_error_t error; - bool success = false; - irecv_mode mode = IRECV_K_RECOVERY_MODE_1; - const char *displayName = nullptr; -}; +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// struct iDescriptorInitDeviceResultRecovery { +// irecv_client_t client = nullptr; +// irecv_device_info deviceInfo; +// irecv_error_t error; +// bool success = false; +// irecv_mode mode = IRECV_K_RECOVERY_MODE_1; +// const char *displayName = nullptr; +// }; -#endif +// #endif void warn(const QString &message, const QString &title = "Warning", QWidget *parent = nullptr); -enum class AddType { Regular, Pairing }; +enum class AddType { Regular, Pairing, Wireless, UpgradeToWireless }; class PlistNavigator { @@ -293,14 +304,14 @@ public: plist_t getNode() const { return current_node; } }; -afc_error_t safe_afc_read_directory(afc_client_t afcClient, idevice_t device, - const char *path, char ***dirs); +// afc_error_t safe_afc_read_directory(afc_client_t afcClient, idevice_t device, +// const char *path, char ***dirs); std::string parse_product_type(const std::string &productType); -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -std::string parse_recovery_mode(irecv_mode productType); -#endif +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// std::string parse_recovery_mode(irecv_mode productType); +// #endif struct MediaEntry { std::string name; @@ -313,114 +324,122 @@ struct AFCFileTree { std::string currentPath; }; -AFCFileTree get_file_tree(afc_client_t afcClient, - const std::string &path = "/"); +// AFCFileTree get_file_tree(afc_client_t afcClient, +// const std::string &path = "/"); -bool detect_jailbroken(afc_client_t afc); +bool detect_jailbroken(AfcClientHandle *afc); -void get_device_info_xml(const char *udid, lockdownd_client_t client, - idevice_t device, pugi::xml_document &infoXml); +void get_device_info_xml(const char *udid, LockdowndClientHandle *client, + pugi::xml_document &infoXml); -iDescriptorInitDeviceResult init_idescriptor_device(const char *udid); - -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -iDescriptorInitDeviceResultRecovery -init_idescriptor_recovery_device(uint64_t ecid); -#endif -bool set_location(idevice_t device, char *lat, char *lon); - -bool shutdown(idevice_t device); - -TakeScreenshotResult take_screenshot(screenshotr_client_t shotr); - -mobile_image_mounter_error_t mount_dev_image(idevice_t device, - unsigned int device_version, - const char *image_dir_path); -struct GetMountedImageResult { - bool success; - std::string sig; - std::string message; +struct WirelessInitArgs { + QString ip; + const IdevicePairingFile *pairing_file; }; +iDescriptorInitDeviceResult +init_idescriptor_device(const QString &udid, + WirelessInitArgs wirelessArgs = {nullptr, nullptr}); -plist_t _get_mounted_image(const char *udid); +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// iDescriptorInitDeviceResultRecovery +// init_idescriptor_recovery_device(uint64_t ecid); +// #endif +// bool set_location(idevice_t device, char *lat, char *lon); -bool restart(std::string udid); +// bool shutdown(idevice_t device); -enum class ImageCompatibility { - Compatible, // Exact match or known compatible version - MaybeCompatible, // Major version matches but minor doesn't - NotCompatible // Not compatible -}; +// TakeScreenshotResult take_screenshot(screenshotr_client_t shotr); -struct ImageInfo { - QString version; - QString dmgPath; - QString sigPath; - ImageCompatibility compatibility = ImageCompatibility::NotCompatible; - bool isDownloaded = false; - bool isMounted = false; -}; +// mobile_image_mounter_error_t mount_dev_image(idevice_t device, +// unsigned int device_version, +// const char *image_dir_path); +// struct GetMountedImageResult { +// bool success; +// std::string sig; +// std::string message; +// }; -/** - * @brief Compare two iPhone product types to determine which is newer - * @param productType First iPhone product type (e.g., "iPhone8,1") - * @param otherProductType Second iPhone product type (e.g., "iPhone7,2") - * @return true if productType is newer than otherProductType, false otherwise - * - * Examples: - * - compare_product_type("iPhone8,1", "iPhone7,2") returns true - * - compare_product_type("iPhone6,1", "iPhone8,1") returns false - * - compare_product_type("iPhone8,2", "iPhone8,1") returns true - */ -bool compare_product_type(std::string productType, - std::string otherProductType); +// plist_t _get_mounted_image(const char *udid); -/** - * @brief Check if two iPhone product types are exactly equal - * @param productType First iPhone product type - * @param otherProductType Second iPhone product type - * @return true if both product types are identical - */ -bool are_product_types_equal(const std::string &productType, - const std::string &otherProductType); +// bool restart(std::string udid); -/** - * @brief Check if first product type is newer than second - * @param productType First iPhone product type - * @param otherProductType Second iPhone product type - * @return true if productType is newer than otherProductType - */ +// enum class ImageCompatibility { +// Compatible, // Exact match or known compatible version +// MaybeCompatible, // Major version matches but minor doesn't +// NotCompatible // Not compatible +// }; + +// struct ImageInfo { +// QString version; +// QString dmgPath; +// QString sigPath; +// ImageCompatibility compatibility = ImageCompatibility::NotCompatible; +// bool isDownloaded = false; +// bool isMounted = false; +// }; + +// /** +// * @brief Compare two iPhone product types to determine which is newer +// * @param productType First iPhone product type (e.g., "iPhone8,1") +// * @param otherProductType Second iPhone product type (e.g., "iPhone7,2") +// * @return true if productType is newer than otherProductType, false +// otherwise +// * +// * Examples: +// * - compare_product_type("iPhone8,1", "iPhone7,2") returns true +// * - compare_product_type("iPhone6,1", "iPhone8,1") returns false +// * - compare_product_type("iPhone8,2", "iPhone8,1") returns true +// */ +// bool compare_product_type(std::string productType, +// std::string otherProductType); + +// /** +// * @brief Check if two iPhone product types are exactly equal +// * @param productType First iPhone product type +// * @param otherProductType Second iPhone product type +// * @return true if both product types are identical +// */ +// bool are_product_types_equal(const std::string &productType, +// const std::string &otherProductType); + +// /** +// * @brief Check if first product type is newer than second +// * @param productType First iPhone product type +// * @param otherProductType Second iPhone product type +// * @return true if productType is newer than otherProductType +// */ bool is_product_type_newer(const std::string &productType, const std::string &otherProductType); -/** - * @brief Check if first product type is older than second - * @param productType First iPhone product type - * @param otherProductType Second iPhone product type - * @return true if productType is older than otherProductType - */ -bool is_product_type_older(const std::string &productType, - const std::string &otherProductType); +// /** +// * @brief Check if first product type is older than second +// * @param productType First iPhone product type +// * @param otherProductType Second iPhone product type +// * @return true if productType is older than otherProductType +// */ +// bool is_product_type_older(const std::string &productType, +// const std::string &otherProductType); -bool query_mobile_gestalt(iDescriptorDevice *id_device, const QStringList &keys, - uint32_t &xml_size, char *&xml_data); -; +// bool query_mobile_gestalt(iDescriptorDevice *id_device, const QStringList +// &keys, +// uint32_t &xml_size, char *&xml_data); +// ; -std::string safeGetXML(const char *key, pugi::xml_node dict); +// std::string safeGetXML(const char *key, pugi::xml_node dict); -void get_battery_info(std::string productType, idevice_t idevice, - bool is_iphone, plist_t &diagnostics); +void get_battery_info(IdeviceProviderHandle *provider, plist_t &diagnostics); -void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d); -void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d); +// void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d); +// void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d); -void fetchAppIconFromApple(QNetworkAccessManager *manager, - const QString &bundleId, - std::function callback); +// void fetchAppIconFromApple(QNetworkAccessManager *manager, +// const QString &bundleId, +// std::function +// callback); -afc_error_t afc2_client_new(idevice_t device, afc_client_t *afc); +// afc_error_t afc2_client_new(idevice_t device, afc_client_t *afc); -void get_cable_info(idevice_t device, plist_t &response); +// void get_cable_info(idevice_t device, plist_t &response); struct NetworkDevice { QString name; // service name @@ -428,7 +447,7 @@ struct NetworkDevice { QString address; // IPv4 or IPv6 address uint16_t port = 22; // SSH port std::map txt; // TXT records - + QString macAddress; // MAC address if available bool operator==(const NetworkDevice &other) const { return name == other.name && address == other.address; @@ -437,13 +456,13 @@ struct NetworkDevice { QPixmap load_heic(const QByteArray &data); -QByteArray read_afc_file_to_byte_array(afc_client_t afcClient, - const char *path); +// QByteArray read_afc_file_to_byte_array(afc_client_t afcClient, +// const char *path); bool isDarkMode(); -instproxy_error_t install_IPA(idevice_t device, afc_client_t afc, - const char *filePath); +// instproxy_error_t install_IPA(idevice_t device, afc_client_t afc, +// const char *filePath); // Helper struct for semantic version comparison struct AppVersion { diff --git a/src/main.cpp b/src/main.cpp index 7cb2815..e16ea84 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,7 @@ */ #include "mainwindow.h" -#include "settingsmanager.h" +// #include "settingsmanager.h" #include #include #include @@ -37,12 +37,12 @@ int main(int argc, char *argv[]) QCoreApplication::setApplicationName("iDescriptor"); QCoreApplication::setApplicationVersion(APP_VERSION); - if (a.arguments().contains("--reset-settings")) { - SettingsManager::sharedInstance()->clear(); - QMessageBox::information(nullptr, "Settings Reset", - "All application settings have been reset to " - "their default values."); - } + // if (a.arguments().contains("--reset-settings")) { + // SettingsManager::sharedInstance()->clear(); + // QMessageBox::information(nullptr, "Settings Reset", + // "All application settings have been reset to + // " "their default values."); + // } #ifdef WIN32 QString appPath = QCoreApplication::applicationDirPath(); QString gstPluginPath = diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6ccdcdc..ec28c5e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -19,19 +19,19 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" -#include "detailwindow.h" -#include "ifusediskunmountbutton.h" -#include "ifusemanager.h" -#include "settingswidget.h" +// #include "detailwindow.h" +// #include "ifusediskunmountbutton.h" +// #include "ifusemanager.h" +// #include "settingswidget.h" #include "appswidget.h" #include "devicemanagerwidget.h" #include "iDescriptor-ui.h" #include "iDescriptor.h" #include "jailbrokenwidget.h" -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -#include "libirecovery.h" -#endif +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// #include "libirecovery.h" +// #endif #include "toolboxwidget.h" #include "welcomewidget.h" #include @@ -42,90 +42,99 @@ #include #include "appcontext.h" -#include "settingsmanager.h" +// #include "settingsmanager.h" +// #include "devicemonitor.h" +#include "networkdevicemanager.h" +#include "networkdeviceswidget.h" #include #include #include #include #include -#ifdef WIN32 -#include "platform/windows/check_deps.h" -#endif +// #ifdef WIN32 +// #include "platform/windows/check_deps.h" +// #endif -void handleCallback(const idevice_event_t *event, void *userData) -{ - printf("Device event received: "); +using namespace IdeviceFFI; - switch (event->event) { - case IDEVICE_DEVICE_ADD: { - /* this should never happen iDescriptor does not support network devices - but for some reason even though we are only listening for USB devices, - we still get network devices on macOS*/ - if (event->conn_type == CONNECTION_NETWORK) { - return; - } - qDebug() << "Device added: " << QString::fromUtf8(event->udid); +// void handleCallback(const idevice_event_t *event, void *userData) +// { +// printf("Device event received: "); - QMetaObject::invokeMethod( - AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection, - Q_ARG(QString, QString::fromUtf8(event->udid)), - Q_ARG(idevice_connection_type, event->conn_type), - Q_ARG(AddType, AddType::Regular)); - break; - } +// switch (event->event) { +// case IDEVICE_DEVICE_ADD: { +// /* this should never happen iDescriptor does not support network +// devices but for some reason even though we are only listening for USB +// devices, we still get network devices on macOS*/ if (event->conn_type +// == CONNECTION_NETWORK) { +// return; +// } +// qDebug() << "Device added: " << QString::fromUtf8(event->udid); - case IDEVICE_DEVICE_REMOVE: { - QMetaObject::invokeMethod(AppContext::sharedInstance(), "removeDevice", - Qt::QueuedConnection, - Q_ARG(QString, QString(event->udid))); - break; - } +// QMetaObject::invokeMethod( +// AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection, +// Q_ARG(QString, QString::fromUtf8(event->udid)), +// Q_ARG(idevice_connection_type, event->conn_type), +// Q_ARG(AddType, AddType::Regular)); +// break; +// } - case IDEVICE_DEVICE_PAIRED: { - if (event->conn_type == CONNECTION_NETWORK) { - qDebug() - << "Network devices are not supported but a network device was " - "received in event listener. Please report this issue."; - return; - } - qDebug() << "Device paired: " << QString::fromUtf8(event->udid); +// case IDEVICE_DEVICE_REMOVE: { +// QMetaObject::invokeMethod(AppContext::sharedInstance(), +// "removeDevice", +// Qt::QueuedConnection, +// Q_ARG(QString, QString(event->udid))); +// break; +// } - QMetaObject::invokeMethod( - AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection, - Q_ARG(QString, QString::fromUtf8(event->udid)), - Q_ARG(idevice_connection_type, event->conn_type), - Q_ARG(AddType, AddType::Pairing)); - break; - } - default: - qDebug() << "Unhandled event: " << event->event; - } -} +// case IDEVICE_DEVICE_PAIRED: { +// if (event->conn_type == CONNECTION_NETWORK) { +// qDebug() +// << "Network devices are not supported but a network device +// was " +// "received in event listener. Please report this issue."; +// return; +// } +// qDebug() << "Device paired: " << QString::fromUtf8(event->udid); -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -void handleCallbackRecovery(const irecv_device_event_t *event, void *userData) -{ +// QMetaObject::invokeMethod( +// AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection, +// Q_ARG(QString, QString::fromUtf8(event->udid)), +// Q_ARG(idevice_connection_type, event->conn_type), +// Q_ARG(AddType, AddType::Pairing)); +// break; +// } +// default: +// qDebug() << "Unhandled event: " << event->event; +// } +// } - switch (event->type) { - case IRECV_DEVICE_ADD: - qDebug() << "Recovery device added: "; - QMetaObject::invokeMethod(AppContext::sharedInstance(), - "addRecoveryDevice", Qt::QueuedConnection, - Q_ARG(uint64_t, event->device_info->ecid)); - break; - case IRECV_DEVICE_REMOVE: - qDebug() << "Recovery device removed: "; - QMetaObject::invokeMethod(AppContext::sharedInstance(), - "removeRecoveryDevice", Qt::QueuedConnection, - Q_ARG(uint64_t, event->device_info->ecid)); - break; - default: - printf("Unhandled recovery event: %d\n", event->type); - } -} -irecv_device_event_context_t context; -#endif +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// void handleCallbackRecovery(const irecv_device_event_t *event, void +// *userData) +// { + +// switch (event->type) { +// case IRECV_DEVICE_ADD: +// qDebug() << "Recovery device added: "; +// QMetaObject::invokeMethod(AppContext::sharedInstance(), +// "addRecoveryDevice", Qt::QueuedConnection, +// Q_ARG(uint64_t, event->device_info->ecid)); +// break; +// case IRECV_DEVICE_REMOVE: +// qDebug() << "Recovery device removed: "; +// QMetaObject::invokeMethod(AppContext::sharedInstance(), +// "removeRecoveryDevice", +// Qt::QueuedConnection, Q_ARG(uint64_t, +// event->device_info->ecid)); +// break; +// default: +// printf("Unhandled recovery event: %d\n", event->type); +// } +// } +// irecv_device_event_context_t context; +// #endif MainWindow *MainWindow::sharedInstance() { @@ -162,27 +171,32 @@ MainWindow::MainWindow(QWidget *parent) this, &MainWindow::updateNoDevicesConnected); m_ZTabWidget->addTab(m_mainStackedWidget, "iDevice"); - auto *appsWidgetTab = - m_ZTabWidget->addTab(AppsWidget::sharedInstance(), "Apps"); - m_ZTabWidget->addTab(new ToolboxWidget(this), "Toolbox"); + // auto *appsWidgetTab = + // m_ZTabWidget->addTab(AppsWidget::sharedInstance(), "Apps"); + // m_ZTabWidget->addTab(new ToolboxWidget(this), "Toolbox"); + m_ZTabWidget->addTab(new QWidget(), "Apps"); // Placeholder for Apps tab + m_ZTabWidget->addTab(new QWidget(), + "Toolbox"); // Placeholder for Toolbox tab + m_ZTabWidget->addTab(new QWidget(), + "Jailbroken"); // Placeholder for Jailbroken tab - auto *jailbrokenWidget = new JailbrokenWidget(this); - m_ZTabWidget->addTab(jailbrokenWidget, "Jailbroken"); + // auto *jailbrokenWidget = new JailbrokenWidget(this); + // m_ZTabWidget->addTab(jailbrokenWidget, "Jailbroken"); m_ZTabWidget->finalizeStyles(); - connect( - appsWidgetTab, &ZTab::clicked, this, - [this](int index) { AppsWidget::sharedInstance()->init(); }, - Qt::SingleShotConnection); + // connect( + // appsWidgetTab, &ZTab::clicked, this, + // [this](int index) { AppsWidget::sharedInstance()->init(); }, + // Qt::SingleShotConnection); - // settings button - ZIconWidget *settingsButton = new ZIconWidget( - QIcon(":/resources/icons/MingcuteSettings7Line.png"), "Settings"); - settingsButton->setCursor(Qt::PointingHandCursor); - settingsButton->setFixedSize(24, 24); - connect(settingsButton, &ZIconWidget::clicked, this, [this]() { - SettingsManager::sharedInstance()->showSettingsDialog(); - }); + // // settings button + // ZIconWidget *settingsButton = new ZIconWidget( + // QIcon(":/resources/icons/MingcuteSettings7Line.png"), "Settings"); + // settingsButton->setCursor(Qt::PointingHandCursor); + // settingsButton->setFixedSize(24, 24); + // connect(settingsButton, &ZIconWidget::clicked, this, [this]() { + // SettingsManager::sharedInstance()->showSettingsDialog(); + // }); ZIconWidget *githubButton = new ZIconWidget( QIcon(":/resources/icons/MdiGithub.png"), "iDescriptor on GitHub"); @@ -204,57 +218,62 @@ MainWindow::MainWindow(QWidget *parent) "QLabel:hover { background-color : #13131319; }"); ui->statusbar->addPermanentWidget(appVersionLabel); ui->statusbar->addPermanentWidget(githubButton); - ui->statusbar->addPermanentWidget(settingsButton); + // ui->statusbar->addPermanentWidget(settingsButton); -#ifdef __linux__ - QList mounted_iFusePaths = iFuseManager::getMountPoints(); + // #ifdef __linux__ + // QList mounted_iFusePaths = iFuseManager::getMountPoints(); - for (const QString &path : mounted_iFusePaths) { - auto *p = new iFuseDiskUnmountButton(path); + // for (const QString &path : mounted_iFusePaths) { + // auto *p = new iFuseDiskUnmountButton(path); - ui->statusbar->addPermanentWidget(p); - connect(p, &iFuseDiskUnmountButton::clicked, this, [this, p, path]() { - bool ok = iFuseManager::linuxUnmount(path); - if (!ok) { - QMessageBox::warning(nullptr, "Unmount Failed", - "Failed to unmount iFuse at " + path + - ". Please try again."); - return; - } - ui->statusbar->removeWidget(p); - p->deleteLater(); - }); - } -#endif + // ui->statusbar->addPermanentWidget(p); + // connect(p, &iFuseDiskUnmountButton::clicked, this, [this, p, + // path]() { + // bool ok = iFuseManager::linuxUnmount(path); + // if (!ok) { + // QMessageBox::warning(nullptr, "Unmount Failed", + // "Failed to unmount iFuse at " + path + // + + // ". Please try again."); + // return; + // } + // ui->statusbar->removeWidget(p); + // p->deleteLater(); + // }); + // } + // #endif -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - irecv_error_t res_recovery = - irecv_device_event_subscribe(&context, handleCallbackRecovery, nullptr); + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // irecv_error_t res_recovery = + // irecv_device_event_subscribe(&context, handleCallbackRecovery, + // nullptr); - if (res_recovery != IRECV_E_SUCCESS) { - qDebug() << "ERROR: Unable to subscribe to recovery device events. " - "Error code:" - << res_recovery; - } - qDebug() << "Subscribed to recovery device events successfully."; -#endif + // if (res_recovery != IRECV_E_SUCCESS) { + // qDebug() << "ERROR: Unable to subscribe to recovery device + // events. " + // "Error code:" + // << res_recovery; + // } + // qDebug() << "Subscribed to recovery device events successfully."; + // #endif - idevice_error_t res = idevice_event_subscribe(handleCallback, nullptr); - if (res != IDEVICE_E_SUCCESS) { - qDebug() << "ERROR: Unable to subscribe to device events. Error code:" - << res; - } - qDebug() << "Subscribed to device events successfully."; - createMenus(); + // idevice_error_t res = idevice_event_subscribe(handleCallback, + // nullptr); if (res != IDEVICE_E_SUCCESS) { + // qDebug() << "ERROR: Unable to subscribe to device events. Error + // code:" + // << res; + // } + // qDebug() << "Subscribed to device events successfully."; + // createMenus(); - UpdateProcedure updateProcedure; - bool packageManagerManaged = false; - bool isPortable = false; - bool skipPrerelease = true; -#ifdef WIN32 - isPortable = !is_iDescriptorInstalled(); - qDebug() << "isPortable=" << isPortable; -#endif + // UpdateProcedure updateProcedure; + // bool packageManagerManaged = false; + // bool isPortable = false; + // bool skipPrerelease = true; + // #ifdef WIN32 + // isPortable = !is_iDescriptorInstalled(); + // qDebug() << "isPortable=" << isPortable; + // #endif /* struct UpdateProcedure { @@ -265,71 +284,225 @@ MainWindow::MainWindow(QWidget *parent) QString boxText; }; */ - switch (ZUpdater::detectPlatform()) { - case Platform::Windows: - updateProcedure = UpdateProcedure{ - !isPortable, - isPortable, - !isPortable, - isPortable ? "New portable version downloaded, app location will " - "be shown after this message" - : "The application will now quit to install the update.", - isPortable ? "New portable version downloaded" - : "Do you want to install the downloaded update now?", - }; - break; - // todo: adjust for pkg managers - case Platform::MacOS: - updateProcedure = UpdateProcedure{ - true, - false, - true, - "The application will now quit and open .dmg file downloaded to " - "\"Downloads\" from there you can drag it to Applications to " - "install.", - "Update downloaded would you like to quit and install the update?", - }; - break; - case Platform::Linux: - // currently only on linux (arch aur) is enabled -#ifdef PACKAGE_MANAGER_MANAGED - packageManagerManaged = true; -#endif - updateProcedure = UpdateProcedure{ - true, - false, - true, - "AppImages we ship are not updateable. New version is downloaded " - "to " - "\"Downloads\". You can start using the new version by launching " - "it " - "from there. You can delete this AppImage version if you like.", - "Update downloaded would you like to quit and open the new " - "version?", - }; - break; - default: - updateProcedure = UpdateProcedure{ - false, false, false, "", "", - }; - } + // switch (ZUpdater::detectPlatform()) { + // case Platform::Windows: + // updateProcedure = UpdateProcedure{ + // !isPortable, + // isPortable, + // !isPortable, + // isPortable ? "New portable version downloaded, app location + // will " + // "be shown after this message" + // : "The application will now quit to install the + // update.", + // isPortable ? "New portable version downloaded" + // : "Do you want to install the downloaded update + // now?", + // }; + // break; + // // todo: adjust for pkg managers + // case Platform::MacOS: + // updateProcedure = UpdateProcedure{ + // true, + // false, + // true, + // "The application will now quit and open .dmg file downloaded + // to " + // "\"Downloads\" from there you can drag it to Applications to + // " "install.", "Update downloaded would you like to quit and + // install the update?", + // }; + // break; + // case Platform::Linux: + // // currently only on linux (arch aur) is enabled + // #ifdef PACKAGE_MANAGER_MANAGED + // packageManagerManaged = true; + // #endif + // updateProcedure = UpdateProcedure{ + // true, + // false, + // true, + // "AppImages we ship are not updateable. New version is + // downloaded " "to " + // "\"Downloads\". You can start using the new version by + // launching " "it " "from there. You can delete this AppImage + // version if you like.", "Update downloaded would you like to + // quit and open the new " "version?", + // }; + // break; + // default: + // updateProcedure = UpdateProcedure{ + // false, false, false, "", "", + // }; + // } - m_updater = new ZUpdater("iDescriptor/iDescriptor", APP_VERSION, - "iDescriptor", updateProcedure, isPortable, - packageManagerManaged, skipPrerelease, this); -#if defined(PACKAGE_MANAGER_MANAGED) && defined(__linux__) - m_updater->setPackageManagerManagedMessage( - QString( - "You seem to have installed iDescriptor using a package manager. " - "Please use %1 to update it.") - .arg(PACKAGE_MANAGER_HINT)); -#endif + // m_updater = new ZUpdater("iDescriptor/iDescriptor", APP_VERSION, + // "iDescriptor", updateProcedure, isPortable, + // packageManagerManaged, skipPrerelease, + // this); + // #if defined(PACKAGE_MANAGER_MANAGED) && defined(__linux__) + // m_updater->setPackageManagerManagedMessage( + // QString( + // "You seem to have installed iDescriptor using a package + // manager. " "Please use %1 to update it.") + // .arg(PACKAGE_MANAGER_HINT)); + // #endif - SettingsManager::sharedInstance()->doIfEnabled( - SettingsManager::Setting::AutoCheckUpdates, [this]() { - qDebug() << "Checking for updates..."; - m_updater->checkForUpdates(); + // SettingsManager::sharedInstance()->doIfEnabled( + // SettingsManager::Setting::AutoCheckUpdates, [this]() { + // qDebug() << "Checking for updates..."; + // m_updater->checkForUpdates(); + // }); + + // Usage in main thread: + m_deviceMonitor = new DeviceMonitorThread(this); + connect( + m_deviceMonitor, &DeviceMonitorThread::deviceEvent, this, + [this](int event, const QString &udid, int conn_type, int addType) { + // Handle device connection + switch (event) { + case DeviceMonitorThread::IDEVICE_DEVICE_ADD: { + /* this should never happen iDescriptor does not + support network devices but for some reason even + though we are only listening for USB devices, we + still get network devices on macOS*/ + if (conn_type == DeviceMonitorThread::CONNECTION_NETWORK) { + return; + } + qDebug() << "Device added: " << udid; + + QMetaObject::invokeMethod( + AppContext::sharedInstance(), "addDevice", + Qt::QueuedConnection, Q_ARG(QString, udid), + Q_ARG( + DeviceMonitorThread::IdeviceConnectionType, + static_cast( + conn_type)), + Q_ARG(AddType, AddType::Regular)); + break; + } + + case DeviceMonitorThread::IDEVICE_DEVICE_REMOVE: { + QMetaObject::invokeMethod(AppContext::sharedInstance(), + "removeDevice", Qt::QueuedConnection, + Q_ARG(QString, udid)); + break; + } + + case DeviceMonitorThread::IDEVICE_DEVICE_PAIRED: { + if (conn_type == DeviceMonitorThread::CONNECTION_NETWORK) { + qDebug() << "Network devices are not supported but a " + "network device was " + "received in event listener. Please report " + "this issue."; + return; + } + qDebug() << "Device paired: " << udid; + + QMetaObject::invokeMethod( + AppContext::sharedInstance(), "addDevice", + Qt::QueuedConnection, Q_ARG(QString, udid), + Q_ARG( + DeviceMonitorThread::IdeviceConnectionType, + static_cast( + conn_type)), + Q_ARG(AddType, AddType::Pairing)); + break; + } + default: + qDebug() << "Unhandled event: " << event; + } }); + + m_deviceMonitor->start(); + + connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this, + [](const std::string &udid, const std::string &wifiMacAddress) { + const IdevicePairingFile *pairingFile = + AppContext::sharedInstance()->getCachedPairingFile( + QString::fromStdString(udid)); + + if (pairingFile) { + // qDebug() << "Device removed, pairing file for UDID" + // << QString::fromStdString(udid) << "MAC" + // << QString::fromStdString(wifiMacAddress) + // << "exists in cache."; + // try to upgrade device to wireless if possible + qDebug() + << "Upgrading device to wireless connection for UDID" + << QString::fromStdString(udid); + QMetaObject::invokeMethod( + AppContext::sharedInstance(), "addDevice", + Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(udid)), + Q_ARG(DeviceMonitorThread::IdeviceConnectionType, + DeviceMonitorThread::CONNECTION_NETWORK), + Q_ARG(AddType, AddType::UpgradeToWireless), + Q_ARG(QString, QString::fromStdString(wifiMacAddress))); + + } else { + qDebug() + << "Device removed, no cached pairing file for UDID" + << QString::fromStdString(udid); + } + }); + + connect(NetworkDeviceManager::sharedInstance(), + &NetworkDeviceManager::deviceAdded, this, + [this](const NetworkDevice &device) { + // const iDescriptorDevice *idevice = + // AppContext::sharedInstance()->getDeviceByMacAddress( + // device.macAddress); + // if (idevice) { + // qDebug() << "Network device matched to connected device:" + // << QString::fromStdString( + // idevice->deviceInfo.deviceName) + // << "MAC:" << device.macAddress; + // // You can now use 'idevice' as needed + // } + // FIXME: both macAddress and udid can be used to get pairing + // file + + if (AppContext::sharedInstance()->getDeviceByMacAddress( + device.macAddress)) { + qDebug() << "Prefering wired connection on device MAC:" + << device.macAddress; + return; + } + + const IdevicePairingFile *pairingFile = + AppContext::sharedInstance()->getCachedPairingFile( + device.macAddress); + + if (!pairingFile) { + qDebug() << "No cached pairing file for network device MAC:" + << device.macAddress + << "Cannot add as wireless device."; + return; + } + + qDebug() << "Trying to add network device with MAC:" + << device.macAddress; + + QMetaObject::invokeMethod( + AppContext::sharedInstance(), "addDevice", + Qt::QueuedConnection, Q_ARG(QString, device.macAddress), + Q_ARG(DeviceMonitorThread::IdeviceConnectionType, + DeviceMonitorThread::CONNECTION_NETWORK), + Q_ARG(AddType, AddType::Wireless), + Q_ARG(QString, device.macAddress)); + + // Handle network device addition if needed + }); + + // NetworkDevicesWidget *m_networkDevicesWidget = new + // NetworkDevicesWidget(); + // m_networkDevicesWidget->setAttribute(Qt::WA_DeleteOnClose); + // m_networkDevicesWidget->setWindowFlag(Qt::Window); + // m_networkDevicesWidget->resize(500, 600); + // // connect(m_networkDevicesWidget, &QObject::destroyed, this, + // // [this]() { m_networkDevicesWidget = nullptr; }); + // m_networkDevicesWidget->show(); } void MainWindow::createMenus() @@ -339,9 +512,9 @@ void MainWindow::createMenus() QAction *aboutAct = new QAction("&About iDescriptor", this); connect(aboutAct, &QAction::triggered, this, [this]() { - QMessageBox::about( - this, "iDescriptor", - "A free, open-source, and cross-platform iDevice management tool."); + QMessageBox::about(this, "iDescriptor", + "A free, open-source, and cross-platform " + "iDevice management tool."); }); actionsMenu->addAction(aboutAct); #endif @@ -357,19 +530,23 @@ void MainWindow::updateNoDevicesConnected() return m_mainStackedWidget->setCurrentIndex(0); // Show Welcome page } int deviceCount = AppContext::sharedInstance()->getConnectedDeviceCount(); - m_connectedDeviceCountLabel->setText( - "iDescriptor: " + QString::number(deviceCount) + - (deviceCount == 1 ? " device" : " devices") + " connected"); + // m_connectedDeviceCountLabel->setText( + // "iDescriptor: " + QString::number(deviceCount) + + // (deviceCount == 1 ? " device" : " devices") + " connected"); m_mainStackedWidget->setCurrentIndex(1); // Show device list page } MainWindow::~MainWindow() { - idevice_event_unsubscribe(); -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT - irecv_device_event_unsubscribe(context); -#endif + // idevice_event_unsubscribe(); + // #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT + // irecv_device_event_unsubscribe(context); + // #endif delete ui; - delete m_updater; - sleep(2); + m_deviceMonitor->requestInterruption(); + // FIXME:QThread: Destroyed while thread '' is still running + // m_deviceMonitor->wait(); + delete m_deviceMonitor; + // delete m_updater; + // sleep(2); } diff --git a/src/mainwindow.h b/src/mainwindow.h index db2938c..85d1bbb 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -23,12 +23,13 @@ #include "ZUpdater.h" #include "devicemanagerwidget.h" #include "iDescriptor.h" -#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT -#include "libirecovery.h" -#endif +#include +// #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT +// #include "libirecovery.h" +// #endif +#include "devicemonitor.h" #include "ztabwidget.h" #include -#include #include QT_BEGIN_NAMESPACE @@ -58,5 +59,6 @@ private: DeviceManagerWidget *m_deviceManager; QStackedWidget *m_mainStackedWidget; QLabel *m_connectedDeviceCountLabel; + DeviceMonitorThread *m_deviceMonitor; }; #endif // MAINWINDOW_H diff --git a/src/networkdevicemanager.cpp b/src/networkdevicemanager.cpp new file mode 100644 index 0000000..1177fb8 --- /dev/null +++ b/src/networkdevicemanager.cpp @@ -0,0 +1,28 @@ +#include "networkdevicemanager.h" + +NetworkDeviceManager *NetworkDeviceManager::sharedInstance() +{ + static NetworkDeviceManager instance; + return &instance; +} + +NetworkDeviceManager::NetworkDeviceManager(QObject *parent) : QObject{parent} +{ + +#ifdef __linux__ + m_networkProvider = new AvahiService(this); + connect(m_networkProvider, &AvahiService::deviceAdded, this, + &NetworkDeviceManager::deviceAdded); + connect(m_networkProvider, &AvahiService::deviceRemoved, this, + &NetworkDeviceManager::deviceRemoved); +#else + m_networkProvider = new DnssdService(this); + connect(m_networkProvider, &DnssdService::deviceAdded, this, + &NetworkDeviceManager::deviceAdded); + connect(m_networkProvider, &DnssdService::deviceRemoved, this, + &NetworkDeviceManager::deviceRemoved); +#endif + + // Start scanning for network devices + m_networkProvider->startBrowsing(); +} diff --git a/src/networkdevicemanager.h b/src/networkdevicemanager.h new file mode 100644 index 0000000..5dfab9b --- /dev/null +++ b/src/networkdevicemanager.h @@ -0,0 +1,29 @@ +#ifndef NETWORKDEVICEMANAGER_H +#define NETWORKDEVICEMANAGER_H + +#include + +#ifdef __linux__ +#include "core/services/avahi/avahi_service.h" +#else +#include "core/services/dnssd/dnssd_service.h" +#endif + +class NetworkDeviceManager : public QObject +{ + Q_OBJECT +public: + explicit NetworkDeviceManager(QObject *parent = nullptr); + +#ifdef __linux__ + AvahiService *m_networkProvider = nullptr; +#else + DnssdService *m_networkProvider = nullptr; +#endif + static NetworkDeviceManager *sharedInstance(); +signals: + void deviceAdded(const NetworkDevice &device); + void deviceRemoved(const QString &deviceName); +}; + +#endif // NETWORKDEVICEMANAGER_H