diff --git a/.gitmodules b/.gitmodules
index 2735eb4..954804b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,9 +4,9 @@
[submodule "lib/win-ifuse"]
path = lib/win-ifuse
url = https://github.com/uncor3/win-ifuse.git
-[submodule "lib/zupdater"]
- path = lib/zupdater
- url = https://github.com/libZQT/ZUpdater
-[submodule "lib/uxplay"]
- path = lib/uxplay
- url = https://github.com/iDescriptor/uxplay
+[submodule "lib/idevice-rs"]
+ path = lib/idevice-rs
+ url = https://github.com/jkcoxson/idevice.git
+[submodule "lib/ztoast"]
+ path = lib/ztoast
+ url = https://github.com/niklashenning/qt-toast.git
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 64890af..cc09ba3 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -1,26 +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",
- "/usr/include/qt6"
- ],
- "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 912d071..d6a8410 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -203,7 +203,9 @@
"qabstractbutton": "cpp",
"qtnetwork": "cpp",
"qtcore": "cpp",
- "qbluetoothdevicediscoveryagent": "cpp",
- "qbluetoothuuid": "cpp"
+ "csetjmp": "cpp",
+ "qthread": "cpp",
+ "qregularexpression": "cpp",
+ "qnetworkaccessmanager": "cpp"
}
}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d57be51..5774aa9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,44 +23,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 Widgets Multimedia MultimediaWidgets Network QuickControls2 SerialPort Positioning Location QuickWidgets)
+find_package(SQLite3 REQUIRED)
# Add QTermWidget
# Prefer CMake-native qtermwidget6, fallback to pkg-config if needed
find_package(qtermwidget6 QUIET)
@@ -88,37 +86,88 @@ 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/debug/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 --manifest-path ${IDEVICE_RS_SOURCE_DIR}/Cargo.toml
+ WORKING_DIRECTORY ${IDEVICE_RS_SOURCE_DIR}
+ COMMENT "Building idevice-rs FFI libraryy"
+ 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)
pkg_check_modules(HEIF REQUIRED IMPORTED_TARGET libheif)
pkg_check_modules(ZIP REQUIRED IMPORTED_TARGET libzip)
@@ -133,35 +182,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
- ${CUSTOM_FIND_LIB_ARGS}
- )
- 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)
@@ -174,8 +209,6 @@ 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
@@ -183,8 +216,102 @@ src/*.cpp
src/core/helpers/*.cpp
src/core/services/*.cpp
src/*.h
-src/*.ui
+# 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
+# src/gallerywidget.cpp
+# src/gallerywidget.h
+# src/photomodel.cpp
+# src/photomodel.h
+# src/core/services/load_heic.cpp
+# src/servicemanager.cpp
+# src/servicemanager.h
+# src/core/services/get_file_tree.cpp
+# src/core/helpers/read_afc_file_to_byte_array.cpp
+# src/heartbeat.h
+# src/zloadingwidget.h
+# src/zloadingwidget.cpp
+# src/mediapreviewdialog.h
+# src/mediapreviewdialog.cpp
+# src/mediastreamer.h
+# src/mediastreamer.cpp
+# src/mediastreamermanager.h
+# src/mediastreamermanager.cpp
+# src/querymobilegestaltwidget.h
+# src/querymobilegestaltwidget.cpp
+# src/core/services/mount_dev_image.cpp
+# src/core/services/get_mounted_image.cpp
+# src/devdiskimageswidget.h
+# src/devdiskimageswidget.cpp
+# src/devdiskmanager.h
+# src/devdiskmanager.cpp
+# src/core/helpers/mounted_image_info_free.cpp
+# src/core/services/get_cable_info.cpp
+# src/cableinfowidget.h
+# src/cableinfowidget.cpp
+# src/livescreenwidget.h
+# src/livescreenwidget.cpp
+# src/virtuallocationwidget.h
+# src/virtuallocationwidget.cpp
)
if(APPLE)
@@ -193,9 +320,7 @@ if(APPLE)
src/core/services/dnssd/dnssd_service.cpp
src/core/services/dnssd/dnssd_service.h
)
-endif()
-
-if (WIN32)
+elseif (WIN32)
list(APPEND PROJECT_SOURCES
src/core/services/dnssd/dnssd_service.cpp
src/core/services/dnssd/dnssd_service.h
@@ -203,9 +328,7 @@ if (WIN32)
file(GLOB WINDOWS_PLATFORM_SOURCES src/platform/windows/*.cpp src/platform/windows/*.h)
list(APPEND PROJECT_SOURCES ${WINDOWS_PLATFORM_SOURCES})
-endif()
-
-if(LINUX)
+else()
list(APPEND PROJECT_SOURCES
src/core/services/avahi/avahi_service.cpp
src/core/services/avahi/avahi_service.h
@@ -226,6 +349,7 @@ endif()
add_subdirectory(lib/uxplay)
add_subdirectory(lib/ipatool-go)
add_subdirectory(lib/zupdater)
+add_subdirectory(lib/ztoast)
if (WIN32)
set(NO_DEPLOY_WIN_IFUSE ON)
@@ -259,6 +383,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
@@ -270,17 +397,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
@@ -292,19 +419,30 @@ target_link_libraries(iDescriptor PRIVATE
uxplay
ipatool-go
ZUpdater
+ ZToast
+ ${IDEVICE_IMPLEMENTATION_LIBS}
+ SQLite::SQLite3
)
-# 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
- ${CMAKE_CURRENT_SOURCE_DIR}/lib/zupdater/src
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/lib
+ # 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
@@ -379,7 +517,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 4abae7c..64ed1dc 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
+

@@ -112,7 +118,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
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/lib/ztoast b/lib/ztoast
new file mode 160000
index 0000000..c7ebd75
--- /dev/null
+++ b/lib/ztoast
@@ -0,0 +1 @@
+Subproject commit c7ebd7514efe138e45d6d1a0ad6c33fd14ae579e
diff --git a/resources.qrc b/resources.qrc
index fc960e4..3a4a582 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -35,6 +35,8 @@
resources/icons/ClarityEyeLine.png
resources/icons/MaterialSymbolsLightImageOutlineSharp.png
resources/icons/MaterialSymbolsFolder.png
+ resources/icons/QlementineIconsWireless116.png
+ resources/icons/UimProcess.png
qml/MapView.qml
resources/iphone.png
resources/ios-wallpapers/iphone-ios4.png
diff --git a/resources/icons/QlementineIconsWireless116.png b/resources/icons/QlementineIconsWireless116.png
new file mode 100644
index 0000000..0fa302d
Binary files /dev/null and b/resources/icons/QlementineIconsWireless116.png differ
diff --git a/resources/icons/UimProcess.png b/resources/icons/UimProcess.png
new file mode 100644
index 0000000..0ff6cff
Binary files /dev/null and b/resources/icons/UimProcess.png differ
diff --git a/src/afcexplorerwidget.cpp b/src/afcexplorerwidget.cpp
index 8ad9928..d9ac881 100644
--- a/src/afcexplorerwidget.cpp
+++ b/src/afcexplorerwidget.cpp
@@ -43,11 +43,9 @@
#include
#include
#include
-#include
-#include
AfcExplorerWidget::AfcExplorerWidget(iDescriptorDevice *device, bool favEnabled,
- afc_client_t afcClient, QString root,
+ AfcClientHandle *afcClient, QString root,
QWidget *parent)
: QWidget(parent), m_device(device), m_favEnabled(favEnabled),
m_afc(afcClient), m_errorMessage("Failed to load directory"), m_root(root)
@@ -208,7 +206,6 @@ void AfcExplorerWidget::loadPath(const QString &path)
AFCFileTree tree = ServiceManager::safeGetFileTree(
m_device, path.toStdString(), true, m_afc);
-
if (!tree.success) {
showErrorState();
return;
@@ -294,11 +291,14 @@ void AfcExplorerWidget::onFileListContextMenu(const QPoint &pos)
if (!currPath.endsWith("/"))
currPath += "/";
+ // FIXME: index
+ int index = 0;
for (QListWidgetItem *selItem : filesToExport) {
QString fileName = selItem->text();
QString devicePath =
currPath == "/" ? "/" + fileName : currPath + fileName;
- exportItems.append(ExportItem(devicePath, fileName));
+ exportItems.append(ExportItem(devicePath, fileName, index));
+ index++;
}
// Start export with singleton - manager will show its own dialog
@@ -349,11 +349,13 @@ void AfcExplorerWidget::onExportClicked()
if (!currPath.endsWith("/"))
currPath += "/";
+ int index = 0;
for (QListWidgetItem *item : filesToExport) {
QString fileName = item->text();
QString devicePath =
currPath == "/" ? "/" + fileName : currPath + fileName;
- exportItems.append(ExportItem(devicePath, fileName));
+ exportItems.append(ExportItem(devicePath, fileName, index));
+ index++;
}
// Start export with singleton - manager will show its own dialog
@@ -376,6 +378,7 @@ void AfcExplorerWidget::exportSelectedFile(QListWidgetItem *item,
// Save to selected directory
QString savePath = directory + "/" + fileName;
+ // FIXME: this should be async
int result = exportFileToPath(m_afc, devicePath.toStdString().c_str(),
savePath.toStdString().c_str());
@@ -404,34 +407,81 @@ void AfcExplorerWidget::exportSelectedFile(QListWidgetItem *item,
even though we are using safe wrappers,
we better move this to services
*/
-int AfcExplorerWidget::exportFileToPath(afc_client_t afc,
+// FIXME: this should be async
+// use connect to signals/slots to notify progress
+// create a progress dialog to show progress
+// dont do this on the main thread
+int AfcExplorerWidget::exportFileToPath(AfcClientHandle *afc,
const char *device_path,
const char *local_path)
{
- uint64_t handle = 0;
- if (ServiceManager::safeAfcFileOpen(m_device, device_path, AFC_FOPEN_RDONLY,
- &handle, m_afc) != AFC_E_SUCCESS) {
- qDebug() << "Failed to open file on device:" << device_path;
+ AfcFileHandle *afcHandle = nullptr;
+ IdeviceFfiError *err_open = ServiceManager::safeAfcFileOpen(
+ m_device, device_path, AfcRdOnly, &afcHandle);
+ if (err_open != nullptr) {
+ qDebug() << "Failed to open file on device:" << device_path
+ << "Error Code:" << err_open->code
+ << "Message:" << err_open->message;
+ idevice_error_free(err_open);
return -1;
}
+
FILE *out = fopen(local_path, "wb");
if (!out) {
qDebug() << "Failed to open local file:" << local_path;
- afc_file_close(afc, handle);
+ IdeviceFfiError *err_close =
+ ServiceManager::safeAfcFileClose(m_device, afcHandle);
+ if (err_close != nullptr) {
+ idevice_error_free(err_close);
+ }
return -1;
}
- char buffer[4096];
- uint32_t bytes_read = 0;
- while (ServiceManager::safeAfcFileRead(m_device, handle, buffer,
- sizeof(buffer), &bytes_read,
- m_afc) == AFC_E_SUCCESS &&
- bytes_read > 0) {
- fwrite(buffer, 1, bytes_read, out);
+ const size_t CHUNK_SIZE = 256 * 1024; // 256KB chunks
+ uint8_t *chunkData = nullptr;
+ size_t bytesRead = 0;
+
+ // Read file in chunks
+ while (true) {
+ IdeviceFfiError *read_err = ServiceManager::safeAfcFileRead(
+ m_device, afcHandle, &chunkData, CHUNK_SIZE, &bytesRead);
+
+ if (read_err != nullptr) {
+ qDebug() << "Error reading file:" << read_err->message;
+ idevice_error_free(read_err);
+ break;
+ }
+
+ if (bytesRead == 0) {
+ // End of file reached
+ break;
+ }
+
+ // Write chunk to local file
+ size_t written = fwrite(chunkData, 1, bytesRead, out);
+
+ // Free the memory allocated by afc_file_read
+ afc_file_read_data_free(chunkData, bytesRead);
+ chunkData = nullptr;
+
+ if (written != bytesRead) {
+ qDebug() << "Failed to write all bytes to local file";
+ fclose(out);
+ ServiceManager::safeAfcFileClose(m_device, afcHandle);
+ return -1;
+ }
}
fclose(out);
- ServiceManager::safeAfcFileClose(m_device, handle, m_afc);
+
+ IdeviceFfiError *err_close =
+ ServiceManager::safeAfcFileClose(m_device, afcHandle);
+ if (err_close != nullptr) {
+ qDebug() << "Failed to close AFC file:" << err_close->message;
+ idevice_error_free(err_close);
+ return -1;
+ }
+
return 0;
}
@@ -467,39 +517,40 @@ void AfcExplorerWidget::onImportClicked()
/*
FIXME : move to services
*/
-int AfcExplorerWidget::importFileToDevice(afc_client_t afc,
+int AfcExplorerWidget::importFileToDevice(AfcClientHandle *afc,
const char *device_path,
const char *local_path)
{
QFile in(local_path);
- if (!in.open(QIODevice::ReadOnly)) {
- qDebug() << "Failed to open local file for import:" << local_path;
- return -1;
- }
+ // if (!in.open(QIODevice::ReadOnly)) {
+ // qDebug() << "Failed to open local file for import:" << local_path;
+ // return -1;
+ // }
- uint64_t handle = 0;
- if (ServiceManager::safeAfcFileOpen(m_device, device_path, AFC_FOPEN_WRONLY,
- &handle, m_afc) != AFC_E_SUCCESS) {
- qDebug() << "Failed to open file on device for writing:" << device_path;
- return -1;
- }
+ // uint64_t handle = 0;
+ // if (ServiceManager::safeAfcFileOpen(m_device, device_path,
+ // AFC_FOPEN_WRONLY,
+ // &handle, m_afc) != AFC_E_SUCCESS) {
+ // qDebug() << "Failed to open file on device for writing:" <<
+ // device_path; return -1;
+ // }
- char buffer[4096];
- qint64 bytesRead;
- while ((bytesRead = in.read(buffer, sizeof(buffer))) > 0) {
- uint32_t bytesWritten = 0;
- if (ServiceManager::safeAfcFileWrite(
- m_device, handle, buffer, static_cast(bytesRead),
- &bytesWritten, m_afc) != AFC_E_SUCCESS ||
- bytesWritten != bytesRead) {
- qDebug() << "Failed to write to device file:" << device_path;
- ServiceManager::safeAfcFileClose(m_device, handle, m_afc);
- in.close();
- return -1;
- }
- }
+ // char buffer[4096];
+ // qint64 bytesRead;
+ // while ((bytesRead = in.read(buffer, sizeof(buffer))) > 0) {
+ // uint32_t bytesWritten = 0;
+ // if (ServiceManager::safeAfcFileWrite(
+ // m_device, handle, buffer, static_cast(bytesRead),
+ // &bytesWritten, m_afc) != AFC_E_SUCCESS ||
+ // bytesWritten != bytesRead) {
+ // qDebug() << "Failed to write to device file:" << device_path;
+ // ServiceManager::safeAfcFileClose(m_device, handle, m_afc);
+ // in.close();
+ // return -1;
+ // }
+ // }
- ServiceManager::safeAfcFileClose(m_device, handle, m_afc);
+ // ServiceManager::safeAfcFileClose(m_device, handle, m_afc);
in.close();
return 0;
}
@@ -823,4 +874,4 @@ void AfcExplorerWidget::goUp()
// Add the new path to history and load it
m_history.push(parentPath);
loadPath(parentPath);
-}
\ No newline at end of file
+}
diff --git a/src/afcexplorerwidget.h b/src/afcexplorerwidget.h
index 6959b91..a20c434 100644
--- a/src/afcexplorerwidget.h
+++ b/src/afcexplorerwidget.h
@@ -38,7 +38,6 @@
#include
#include
#include
-#include
class ExportManager;
class ExportProgressDialog;
@@ -49,7 +48,7 @@ class AfcExplorerWidget : public QWidget
public:
explicit AfcExplorerWidget(iDescriptorDevice *device = nullptr,
bool favEnabled = false,
- afc_client_t afcClient = nullptr,
+ AfcClientHandle *afcClient = nullptr,
QString root = "/", QWidget *parent = nullptr);
void navigateToPath(const QString &path);
void goHome();
@@ -90,7 +89,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;
@@ -111,9 +110,9 @@ private:
void setupContextMenu();
void exportSelectedFile(QListWidgetItem *item);
void exportSelectedFile(QListWidgetItem *item, const QString &directory);
- int exportFileToPath(afc_client_t afc, const char *device_path,
+ int exportFileToPath(AfcClientHandle *afc, const char *device_path,
const char *local_path);
- int importFileToDevice(afc_client_t afc, const char *device_path,
+ int importFileToDevice(AfcClientHandle *afc, const char *device_path,
const char *local_path);
void updateNavStyles();
void updateButtonStates();
diff --git a/src/appcontext.cpp b/src/appcontext.cpp
index 208bd25..aaa77e3 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,92 +39,328 @@ 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} {}
-
-void AppContext::addDevice(QString udid, idevice_connection_type conn_type,
- AddType addType)
+AppContext::AppContext(QObject *parent) : QObject{parent}
{
- try {
- iDescriptorInitDeviceResult initResult =
- init_idescriptor_device(udid.toStdString().c_str());
+ cachePairedDevices();
+}
- qDebug() << "init_idescriptor_device success ?: " << initResult.success;
- qDebug() << "init_idescriptor_device error code: " << initResult.error;
+void AppContext::cachePairedDevices()
+{
- 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();
+/*
+ does not work on macOS because we cannot read /var/db/lockdown without root perm
+*/
+#ifndef __APPLE__
+ QDir lockdowndir(LOCKDOWN_PATH);
+ if (!lockdowndir.exists()) {
+ return;
+ }
+
+ // Load cached pairing files
+ QStringList pairingFiles =
+ lockdowndir.entryList(QStringList() << "*.plist", QDir::Files);
+
+ qDebug() << "Parsing cached pairing files in /var/lib/lockdown:";
+ for (const QString &fileName : pairingFiles) {
+ qDebug() << "Found pairing file:" << fileName;
+ plist_t fileData = nullptr;
+ plist_read_from_file(
+ lockdowndir.filePath(fileName).toUtf8().constData(), &fileData,
+ NULL);
+
+ if (!fileData) {
+ continue;
+ }
+ plist_print(fileData);
+ const std::string wifiMacAddress =
+ PlistNavigator(fileData)["WiFiMACAddress"].getString();
+ // plist_free(fileData);
+ bool isCompatible = !wifiMacAddress.empty();
+ // TODO: !important invalidate expired pairing files
+ // sometimes there is no WiFiMACAddress
+ if (!isCompatible) {
+ continue;
+ }
+ qDebug() << "Found pairing file for MAC"
+ << QString::fromStdString(wifiMacAddress);
+
+ qDebug() << "Caching pairing file for MAC"
+ << QString::fromStdString(wifiMacAddress) << "Local Path"
+ << lockdowndir.filePath(fileName);
+ m_pairingFileCache[QString::fromStdString(wifiMacAddress)] =
+ lockdowndir.filePath(fileName);
+ }
+#else
+ // FIXME: implement caching for macOS
+ /* MacOS */
+ qDebug() << "Caching paired network devices from usbmuxd";
+ auto conn = UsbmuxdConnection::default_new(0);
+ if (conn.is_err()) {
+ qDebug() << "ERROR: Failed to connect to usbmuxd!";
+ // return 1;
+ }
+
+ auto devices = conn.unwrap().get_devices();
+ if (devices.is_err()) {
+ qDebug() << "ERROR: Failed to get device list!";
+ // return 1;
+ }
+
+ for (const auto &device : devices.unwrap()) {
+ auto conn_type = device.get_connection_type();
+ if (conn_type.is_some() &&
+ conn_type.unwrap().to_string() == "Network") {
+ auto udid = device.get_udid();
+ if (udid.is_some()) {
+ qDebug() << "Found network device with UDID:"
+ << QString::fromStdString(udid.unwrap());
+
+ auto pairing_file =
+ conn.unwrap().get_pair_record(udid.unwrap());
+
+ uint8_t *plist_data = nullptr;
+ size_t plist_size = 0;
+ IdeviceFfiError *error = idevice_pairing_file_serialize(
+ pairing_file.unwrap().raw(), &plist_data, &plist_size);
+
+ if (error == nullptr) {
+ plist_t root_node = nullptr;
+ plist_from_xml((const char *)plist_data, plist_size,
+ &root_node);
+
+ if (root_node) {
+ plist_t wifi_mac_node =
+ plist_dict_get_item(root_node, "WiFiMACAddress");
+
+ if (wifi_mac_node &&
+ plist_get_node_type(wifi_mac_node) ==
+ PLIST_STRING) {
+ char *mac_address = nullptr;
+ plist_get_string_val(wifi_mac_node, &mac_address);
+
+ if (mac_address) {
+ qDebug() << "Adding to cache"
+ << QString::fromUtf8(mac_address);
+ m_pairingFileCache[QString::fromUtf8(
+ mac_address)] =
+ QString::fromStdString("/var/db/lockdown/" +
+ udid.unwrap() +
+ ".plist");
+ free(mac_address);
}
- });
- }
- } 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{
- .udid = udid.toStdString(),
- .conn_type = conn_type,
- .device = initResult.device,
- .deviceInfo = initResult.deviceInfo,
- .afcClient = initResult.afcClient,
- .afc2Client = initResult.afc2Client,
- };
- m_devices[device->udid] = device;
- if (addType == AddType::Regular) {
- SettingsManager::sharedInstance()->doIfEnabled(
- SettingsManager::Setting::AutoRaiseWindow, []() {
- if (MainWindow *mainWindow = MainWindow::sharedInstance()) {
- mainWindow->raise();
- mainWindow->activateWindow();
+ plist_free(root_node);
}
- });
-
- emit deviceAdded(device);
- emit deviceChange();
- return;
+ free(plist_data);
+ }
+ // qDebug() << "Wireless device UDID:"
+ // << QString::fromStdString(udid.unwrap())
+ // << "Pairing file retrieval"
+ // << (error == nullptr
+ // ? "succeeded"
+ // : QString::fromStdString(error->message));
+ // Clean up
+ // idevice_pairing_file_free(pairing_file.unwrap().raw());
+ }
+ } else if (conn_type.is_some()) {
+ auto udid = device.get_udid();
+ if (udid.is_some()) {
+ qDebug() << "Found USB device with UDID:"
+ << QString::fromStdString(udid.unwrap());
+ }
}
- emit devicePaired(device);
- emit deviceChange();
- m_pendingDevices.removeAll(udid);
+ }
+#endif
+}
+void AppContext::addDevice(QString udid,
+ DeviceMonitorThread::IdeviceConnectionType conn_type,
+ AddType addType, QString wifiMacAddress)
+{
+
+ try {
+ // iDescriptorInitDeviceResult initResult;
+ auto initResult = std::make_shared();
+ QFuture future = QtConcurrent::run([this, udid, conn_type,
+ addType, wifiMacAddress,
+ initResult]() {
+ if (addType == AddType::UpgradeToWireless) {
+ // udid is mac address here
+ const QString _pairingFilePath = getCachedPairingFile(udid);
+
+ if (_pairingFilePath.isEmpty()) {
+ qDebug() << "Cannot upgrade to wireless, no cached 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, _pairingFilePath});
+ } else {
+ qDebug() << "No network device found with MAC address:"
+ << wifiMacAddress;
+ return;
+ }
+ } else if (addType == AddType::Wireless) {
+ // FIXME: its not udid here its macAddress
+ const QString _pairingFilePath = getCachedPairingFile(udid);
+
+ if (_pairingFilePath.isEmpty()) {
+ qDebug() << "Cannot upgrade to wireless, no cached pairing "
+ "file for"
+ << udid;
+ return;
+ }
+
+ QList networkDevices =
+ NetworkDeviceManager::sharedInstance()
+ ->m_networkProvider->getNetworkDevices();
+
+ // todo : retry logic if not found
+ 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, _pairingFilePath});
+ } else {
+ qDebug() << "No network device found with MAC address:"
+ << wifiMacAddress;
+ return;
+ }
+ }
+
+ else {
+
+ *initResult = init_idescriptor_device(udid, {nullptr, nullptr});
+ }
+ });
+ QFutureWatcher *watcher = new QFutureWatcher();
+ watcher->setFuture(future);
+ connect(watcher, &QFutureWatcher::finished, this,
+ [this, udid, initResult, addType, conn_type, watcher]() {
+ watcher->deleteLater();
+ qDebug() << "init_idescriptor_device success ?: "
+ << initResult->success;
+ // qDebug() << "init_idescriptor_device error code: " <<
+ // initResult.error;
+ if (!initResult->success) {
+ qDebug() << "Failed to initialize device with UDID: "
+ << udid;
+ 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{
+ .udid = udid.toStdString(),
+ .conn_type = conn_type,
+ .provider = initResult->provider,
+ .deviceInfo = initResult->deviceInfo,
+ .afcClient = initResult->afcClient,
+ .afc2Client = initResult->afc2Client,
+ .lockdown = initResult->lockdown,
+ .mutex = new std::recursive_mutex(),
+ .imageMounter = initResult->imageMounter,
+ .diagRelay = initResult->diagRelay,
+ .locationSimulation = initResult->locationSimulation,
+ .heartbeatThread = initResult->heartbeatThread};
+ m_devices[device->udid] = device;
+ if (addType == AddType::Regular) {
+ 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();
+ return;
+ }
+ emit devicePaired(device);
+ emit deviceChange();
+ m_pendingDevices.removeAll(udid);
+ });
} catch (const std::exception &e) {
qDebug() << "Exception in onDeviceAdded: " << e.what();
}
@@ -130,19 +368,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();
@@ -168,7 +406,7 @@ 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);
@@ -177,32 +415,39 @@ void AppContext::removeDevice(QString _udid)
afc_client_free(device->afcClient);
if (device->afc2Client)
afc_client_free(device->afc2Client);
+ // idevice_free(device->device);
- idevice_free(device->device);
-
+ if (device->heartbeatThread) {
+ device->heartbeatThread->requestInterruption();
+ device->heartbeatThread->wait();
+ delete device->heartbeatThread;
+ }
+
+ 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;
+ // std::lock_guard lock(*deviceInfo->mutex);
+ // delete deviceInfo->mutex;
+ // delete deviceInfo;
}
#endif
@@ -216,68 +461,76 @@ 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;
+ // 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()
{
+ // FIXME: mutex?
for (auto device : m_devices) {
- emit deviceRemoved(device->udid);
+ emit deviceRemoved(device->udid, device->deviceInfo.wifiMacAddress);
if (device->afcClient)
afc_client_free(device->afcClient);
if (device->afc2Client)
afc_client_free(device->afc2Client);
- idevice_free(device->device);
- delete device;
+ // idevice_free(device->device);
+
+ if (device->heartbeatThread) {
+ device->heartbeatThread->requestInterruption();
+ device->heartbeatThread->wait();
+ delete device->heartbeatThread;
+ }
}
-#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT
- for (auto recoveryDevice : m_recoveryDevices) {
- emit recoveryDeviceRemoved(recoveryDevice->ecid);
- 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)
@@ -300,4 +553,77 @@ void AppContext::setCurrentDeviceSelection(const DeviceSelection &selection)
const DeviceSelection &AppContext::getCurrentDeviceSelection() const
{
return m_currentSelection;
+}
+
+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,
+ const QString &pairingFilePath)
+{
+ m_pairingFileCache.insert(udid, pairingFilePath);
+}
+const QString AppContext::getCachedPairingFile(const QString &udid) const
+{
+ QString pairingFile;
+
+ // Retrieve the pairing file from the cache
+ if (m_pairingFileCache.contains(udid)) {
+ pairingFile = m_pairingFileCache.value(udid);
+ } else {
+ // FIXME: mac support
+ // IdevicePairingFile* pairing_file = nullptr;
+ // const char* file_path = udid.toUtf8().constData();
+ // IdeviceFfiError* err = idevice_pairing_file_read(file_path,
+ // &pairing_file); if (err == nullptr || pairing_file == nullptr) {
+ // pairingFile = QString::fromUtf8(file_path);
+ // } else {
+ // qDebug() << "Failed to read pairing file for UDID:" << udid <<
+ // "Error:" << err->message; idevice_error_free(err);
+ // }
+ }
+
+ return pairingFile;
+}
+
+void AppContext::heartbeatFailed(const QString &macAddress, int tries)
+{
+ emit deviceHeartbeatFailed(macAddress, tries);
+}
+
+void AppContext::tryToConnectToNetworkDevice(const QString &macAddress)
+{
+
+ // force refresh macAddress-udid mapping
+ cachePairedDevices();
+
+ QList networkDevices =
+ NetworkDeviceManager::sharedInstance()
+ ->m_networkProvider->getNetworkDevices();
+
+ auto it =
+ std::find_if(networkDevices.constBegin(), networkDevices.constEnd(),
+ [macAddress](const NetworkDevice &device) {
+ return device.macAddress.compare(
+ macAddress, Qt::CaseInsensitive) == 0;
+ });
+
+ if (it != networkDevices.constEnd()) {
+ QMetaObject::invokeMethod(
+ AppContext::sharedInstance(), "addDevice", Qt::QueuedConnection,
+ Q_ARG(QString, macAddress),
+ Q_ARG(DeviceMonitorThread::IdeviceConnectionType,
+ DeviceMonitorThread::CONNECTION_NETWORK),
+ Q_ARG(AddType, AddType::Wireless), Q_ARG(QString, macAddress));
+ } else {
+ qDebug() << "No network device found with MAC address:" << macAddress;
+ }
}
\ No newline at end of file
diff --git a/src/appcontext.h b/src/appcontext.h
index 3ba8c26..febac7c 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,40 @@ public:
QList getAllDevices();
explicit AppContext(QObject *parent = nullptr);
bool noDevicesConnected() const;
+ // QMap
+ void cachePairingFile(const QString &udid, const QString &pairingFilePath);
+ const QString getCachedPairingFile(const QString &udid) const;
-#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT
- QList getAllRecoveryDevices();
-#endif
+ void tryToConnectToNetworkDevice(const QString &macAddress);
+ // #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("");
+ QMap m_pairingFileCache;
+ void cachePairedDevices();
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();
@@ -72,10 +81,14 @@ signals:
*/
void deviceChange();
void currentDeviceSelectionChanged(const DeviceSelection &selection);
+ void deviceHeartbeatFailed(const QString &macAddress, int tries);
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());
+ void heartbeatFailed(const QString &macAddress, int tries);
+ // void heartbeatThreadExited(const QString &macAddress);
#ifdef ENABLE_RECOVERY_DEVICE_SUPPORT
void addRecoveryDevice(uint64_t ecid);
void removeRecoveryDevice(uint64_t ecid);
diff --git a/src/appdownloadbasedialog.cpp b/src/appdownloadbasedialog.cpp
index 04d508b..2f60bdc 100644
--- a/src/appdownloadbasedialog.cpp
+++ b/src/appdownloadbasedialog.cpp
@@ -72,7 +72,8 @@ AppDownloadBaseDialog::AppDownloadBaseDialog(const QString &appName,
void AppDownloadBaseDialog::startDownloadProcess(const QString &bundleId,
const QString &outputDir,
int index,
- bool promptToOpenDir)
+ bool promptToOpenDir,
+ bool close)
{
if (bundleId.isEmpty()) {
@@ -86,12 +87,12 @@ void AppDownloadBaseDialog::startDownloadProcess(const QString &bundleId,
m_actionButton->setEnabled(false);
m_operationInProgress = true;
- tryToDownload(bundleId, outputDir, promptToOpenDir);
+ tryToDownload(bundleId, outputDir, promptToOpenDir, close);
}
void AppDownloadBaseDialog::tryToDownload(const QString &bundleId,
const QString &outputDir,
- bool promptToOpenDir)
+ bool promptToOpenDir, bool close)
{
AppStoreManager *manager = AppStoreManager::sharedInstance();
if (!manager) {
@@ -117,7 +118,7 @@ void AppDownloadBaseDialog::tryToDownload(const QString &bundleId,
manager->downloadApp(
bundleId, outputDir, "", acquireLicense,
- [safeThis, promptToOpenDir, outputDir](int result) {
+ [safeThis, promptToOpenDir, outputDir, close](int result) {
if (!safeThis) {
return;
}
@@ -146,7 +147,8 @@ void AppDownloadBaseDialog::tryToDownload(const QString &bundleId,
}
}
}
- safeThis->accept();
+ if (close)
+ safeThis->accept();
} else { // Failure
// 3 attempts
if (safeThis->m_tries < 3) {
@@ -166,7 +168,8 @@ void AppDownloadBaseDialog::tryToDownload(const QString &bundleId,
"in. Error code: %2")
.arg(safeThis->m_appName)
.arg(result));
- safeThis->reject();
+ if (close)
+ safeThis->reject();
}
},
progressCallback);
diff --git a/src/appdownloadbasedialog.h b/src/appdownloadbasedialog.h
index 79bbe2e..2810f1b 100644
--- a/src/appdownloadbasedialog.h
+++ b/src/appdownloadbasedialog.h
@@ -44,13 +44,13 @@ protected:
void reject() override;
void startDownloadProcess(const QString &bundleId,
const QString &workingDir, int index,
- bool promptToOpenDir = true);
+ bool promptToOpenDir = true, bool close = false);
void checkDownloadProgress(const QString &logFilePath,
const QString &appName,
const QString &outputDir);
void addProgressBar(int index);
void tryToDownload(const QString &bundleId, const QString &outputDir,
- bool promptToOpenDir);
+ bool promptToOpenDir, bool close = false);
QProgressBar *m_progressBar;
QTimer *m_progressTimer;
QProcess *m_downloadProcess;
diff --git a/src/appinstalldialog.cpp b/src/appinstalldialog.cpp
index 0493cf6..97afa78 100644
--- a/src/appinstalldialog.cpp
+++ b/src/appinstalldialog.cpp
@@ -21,6 +21,7 @@
#include "appcontext.h"
#include "appdownloadbasedialog.h"
#include "iDescriptor.h"
+#include "servicemanager.h"
#include
#include
#include
@@ -151,46 +152,59 @@ void AppInstallDialog::updateDeviceList()
}
void AppInstallDialog::performInstallation(const QString &ipaPath,
+ const QString &ipaName,
const QString &deviceUdid)
{
m_statusLabel->setText("Installing app...");
// Setup install watcher
- m_installWatcher = new QFutureWatcher(this);
- connect(m_installWatcher, &QFutureWatcher::finished, this, [this]() {
- int result = m_installWatcher->result();
- m_installWatcher->deleteLater();
- m_installWatcher = nullptr;
+ m_installWatcher = new QFutureWatcher(this);
+ connect(
+ m_installWatcher, &QFutureWatcher::finished, this,
+ [this]() {
+ IdeviceFfiError *result = m_installWatcher->result();
+ m_installWatcher->deleteLater();
+ m_installWatcher = nullptr;
- if (result == 0) {
- m_statusLabel->setText("Installation completed successfully!");
- m_statusLabel->setStyleSheet(
- "font-size: 14px; color: #34C759; padding: 5px;");
- QMessageBox::information(this, "Success",
- "App installed successfully!");
- accept();
- } else {
- m_statusLabel->setText("Installation failed");
- m_statusLabel->setStyleSheet(
- "font-size: 14px; color: #FF3B30; padding: 5px;");
- QMessageBox::critical(
- this, "Error",
- QString("Installation failed with error code: %1").arg(result));
- }
- });
+ if (result == nullptr) {
+ m_statusLabel->setText("Installation completed successfully!");
+ m_statusLabel->setStyleSheet(
+ "font-size: 14px; color: #34C759; padding: 5px;");
+ QMessageBox::information(this, "Success",
+ "App installed successfully!");
+ accept();
+ } else {
+ m_statusLabel->setText("Installation failed");
+ m_statusLabel->setStyleSheet(
+ "font-size: 14px; color: #FF3B30; padding: 5px;");
+ QMessageBox::critical(
+ this, "Error",
+ QString(
+ "Installation failed with message %1 and error code %2")
+ .arg(QString::fromUtf8(result->message))
+ .arg(result->code));
+ idevice_error_free(result);
+ reject();
+ }
+ });
// Run installation in background thread
- QFuture future = QtConcurrent::run([ipaPath, deviceUdid]() -> int {
- iDescriptorDevice *device =
- AppContext::sharedInstance()->getDevice(deviceUdid.toStdString());
- if (!device) {
- return -1;
- }
+ QFuture future = QtConcurrent::run(
+ [ipaPath, ipaName, deviceUdid]() -> IdeviceFfiError * {
+ iDescriptorDevice *device = AppContext::sharedInstance()->getDevice(
+ deviceUdid.toStdString());
+ if (!device) {
+ return nullptr;
+ }
- instproxy_error_t ret = install_IPA(device->device, device->afcClient,
- ipaPath.toStdString().c_str());
- return static_cast(ret);
- });
+ IdeviceFfiError *err = ServiceManager::install_IPA(
+ device, ipaPath.toStdString().c_str(),
+ ipaName.toStdString().c_str());
+ if (err != nullptr) {
+ return err;
+ }
+ return nullptr;
+ });
m_installWatcher->setFuture(future);
}
@@ -229,43 +243,44 @@ void AppInstallDialog::onInstallClicked()
return;
}
- startDownloadProcess(m_bundleId, m_tempDir->path(), buttonIndex, false);
- connect(this, &AppDownloadBaseDialog::downloadFinished, this,
- [this, selectedDevice](bool success) {
- if (success) {
- qDebug() << "Download finished, starting installation...";
- /*
- FIXME: libipatool generates random id and appends that
- to the downloaded IPA filename, so we need to search for
- it.
- */
- // Find the actual downloaded IPA file
- QDir outDir(m_tempDir->path());
- QStringList filters;
- filters << m_bundleId + "*.ipa";
- QStringList matches =
- outDir.entryList(filters, QDir::Files, QDir::Time);
- if (matches.isEmpty()) {
- m_statusLabel->setText(
- "Download failed - IPA not found");
- m_statusLabel->setStyleSheet(
- "font-size: 14px; color: #FF3B30; padding: 5px;");
- QMessageBox::critical(
- this, "Error",
- QString("Downloaded IPA not found in %1")
- .arg(outDir.absolutePath()));
- return;
- }
-
- QString ipaFile = outDir.filePath(matches.first());
- performInstallation(ipaFile, selectedDevice);
-
- } else {
- m_statusLabel->setText("Download failed");
+ startDownloadProcess(m_bundleId, m_tempDir->path(), buttonIndex, false,
+ false);
+ connect(
+ this, &AppDownloadBaseDialog::downloadFinished, this,
+ [this, selectedDevice](bool success) {
+ if (success) {
+ qDebug() << "Download finished, starting installation...";
+ /*
+ FIXME: libipatool generates random id and appends that
+ to the downloaded IPA filename, so we need to search for
+ it.
+ */
+ // Find the actual downloaded IPA file
+ QDir outDir(m_tempDir->path());
+ QStringList filters;
+ filters << m_bundleId + "*.ipa";
+ QStringList matches =
+ outDir.entryList(filters, QDir::Files, QDir::Time);
+ if (matches.isEmpty()) {
+ m_statusLabel->setText("Download failed - IPA not found");
m_statusLabel->setStyleSheet(
"font-size: 14px; color: #FF3B30; padding: 5px;");
+ QMessageBox::critical(
+ this, "Error",
+ QString("Downloaded IPA not found in %1")
+ .arg(outDir.absolutePath()));
+ return;
}
- });
+ qDebug() << "Found downloaded IPA:" << matches.first();
+ QString ipaFile = outDir.filePath(matches.first());
+ performInstallation(ipaFile, matches.first(), selectedDevice);
+
+ } else {
+ m_statusLabel->setText("Download failed");
+ m_statusLabel->setStyleSheet(
+ "font-size: 14px; color: #FF3B30; padding: 5px;");
+ }
+ });
}
void AppInstallDialog::reject()
diff --git a/src/appinstalldialog.h b/src/appinstalldialog.h
index 5d38fd7..b91ab5d 100644
--- a/src/appinstalldialog.h
+++ b/src/appinstalldialog.h
@@ -25,8 +25,9 @@
#include
#include
#include
-#include
#include
+#include
+#include "iDescriptor.h"
class AppInstallDialog : public AppDownloadBaseDialog
{
@@ -48,11 +49,12 @@ private:
QComboBox *m_deviceCombo;
QString m_bundleId;
QLabel *m_statusLabel;
- QFutureWatcher *m_installWatcher;
+ QFutureWatcher *m_installWatcher;
QTemporaryDir *m_tempDir = nullptr;
QNetworkAccessManager *m_manager = nullptr;
void updateDeviceList();
- void performInstallation(const QString &ipaPath, const QString &deviceUdid);
+ void performInstallation(const QString &ipaPath, const QString &ipaName,
+ const QString &deviceUdid);
};
#endif // APPINSTALLDIALOG_H
diff --git a/src/cableinfowidget.cpp b/src/cableinfowidget.cpp
index 7b93109..b85b9b2 100644
--- a/src/cableinfowidget.cpp
+++ b/src/cableinfowidget.cpp
@@ -19,6 +19,7 @@
#include "cableinfowidget.h"
#include "appcontext.h"
+#include "servicemanager.h"
#include
#include
#include
@@ -29,7 +30,6 @@ CableInfoWidget::CableInfoWidget(iDescriptorDevice *device, QWidget *parent)
: QWidget(parent), m_device(device), m_response(nullptr)
{
setupUI();
- initCableInfo();
connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
[this](const std::string &udid) {
if (m_device->udid == udid) {
@@ -37,12 +37,13 @@ CableInfoWidget::CableInfoWidget(iDescriptorDevice *device, QWidget *parent)
this->deleteLater();
}
});
+ QTimer::singleShot(200, this, &CableInfoWidget::initCableInfo);
}
void CableInfoWidget::setupUI()
{
setWindowTitle("Cable Information - iDescriptor");
- m_mainLayout = new QVBoxLayout(this);
+ m_mainLayout = new QVBoxLayout();
m_mainLayout->setSpacing(20);
m_mainLayout->setContentsMargins(20, 20, 20, 20);
@@ -57,7 +58,14 @@ void CableInfoWidget::setupUI()
new QLabel("Please wait while we analyze the connected cable.");
m_descriptionLabel->setStyleSheet("font-size: 9px;");
+ QPushButton *redoButton = new QPushButton("Re-analyze");
+ connect(redoButton, &QPushButton::clicked, this, [this]() {
+ m_loadingWidget->showLoading();
+ QTimer::singleShot(200, this, &CableInfoWidget::initCableInfo);
+ });
headerLayout->addWidget(m_statusLabel);
+ headerLayout->addStretch();
+ headerLayout->addWidget(redoButton);
m_mainLayout->addLayout(headerLayout);
@@ -70,19 +78,43 @@ void CableInfoWidget::setupUI()
m_mainLayout->addWidget(m_descriptionLabel);
m_mainLayout->addWidget(m_infoWidget);
m_mainLayout->addStretch();
+ m_loadingWidget = new ZLoadingWidget(true, this);
+ m_loadingWidget->setupContentWidget(m_mainLayout);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(m_loadingWidget);
+
+ QVBoxLayout *errorLayout = new QVBoxLayout();
+ m_errorLabel = new QLabel();
+ m_errorLabel->setAlignment(Qt::AlignCenter);
+ errorLayout->addStretch();
+ errorLayout->addWidget(m_errorLabel);
+
+ QPushButton *retryButton = new QPushButton("Retry");
+ retryButton->setMaximumWidth(retryButton->sizeHint().width());
+ connect(retryButton, &QPushButton::clicked, this, [this]() {
+ m_loadingWidget->showLoading();
+ QTimer::singleShot(200, this, &CableInfoWidget::initCableInfo);
+ });
+ errorLayout->addWidget(retryButton, 0, Qt::AlignHCenter);
+ errorLayout->addStretch();
+
+ m_loadingWidget->setupErrorWidget(errorLayout);
}
void CableInfoWidget::initCableInfo()
{
- if (!m_device || !m_device->device) {
- m_statusLabel->setText("Something went wrong (no device ?)");
- m_statusLabel->setStyleSheet(
+ if (!m_device) {
+ m_errorLabel->setText("Something went wrong (no device ?)");
+ m_errorLabel->setStyleSheet(
"QLabel { color: #dc3545; font-size: 18px; font-weight: bold; }");
+ m_loadingWidget->showError();
return;
}
m_statusLabel->setText("Analyzing cable...");
- get_cable_info(m_device->device, m_response);
+ ServiceManager::getCableInfo(m_device, m_response);
analyzeCableInfo();
updateUI();
@@ -97,15 +129,13 @@ void CableInfoWidget::analyzeCableInfo()
if (!m_response) {
return;
}
-
- PlistNavigator nav(m_response);
- PlistNavigator ioreg = nav["IORegistry"];
+ plist_print(m_response);
+ PlistNavigator ioreg(m_response);
if (!ioreg.valid()) {
return;
}
-
- m_cableInfo.isConnected = true;
+ m_cableInfo.isConnected = ioreg["ConnectionActive"].getBool();
// Check if genuine (Apple manufacturer and valid model info)
m_cableInfo.manufacturer = QString::fromStdString(
@@ -197,6 +227,14 @@ void CableInfoWidget::updateUI()
delete item;
}
+ if (!m_cableInfo.isConnected) {
+ m_errorLabel->setText(
+ QString("%1 does not seem to be connected to any cable.")
+ .arg(m_device->deviceInfo.productType));
+ m_loadingWidget->showError();
+ return;
+ }
+
// Update status and icon based on cable type
QString statusText;
QString statusStyle;
@@ -204,6 +242,7 @@ void CableInfoWidget::updateUI()
m_descriptionLabel->setText("Please note that this check may not be "
"absolute guarantee of authenticity.");
if (m_cableInfo.isGenuine) {
+ // todo: type-c to type-c
statusText = QString("✅ Genuine %1")
.arg(m_cableInfo.isTypeC ? "USB-C to Lightning Cable"
: "Lightning Cable");
@@ -284,6 +323,7 @@ void CableInfoWidget::updateUI()
createInfoRow(m_infoLayout, row++, "Supported Transports:",
m_cableInfo.supportedTransports.join(", "));
}
+ m_loadingWidget->stop(true);
}
void CableInfoWidget::createInfoRow(QGridLayout *layout, int row,
diff --git a/src/cableinfowidget.h b/src/cableinfowidget.h
index bd28801..be6de40 100644
--- a/src/cableinfowidget.h
+++ b/src/cableinfowidget.h
@@ -21,6 +21,7 @@
#define CABLEINFOWIDGET_H
#include "iDescriptor.h"
+#include "zloadingwidget.h"
#include
#include
#include
@@ -29,7 +30,6 @@
#include
#include
#include
-#include
class CableInfoWidget : public QWidget
{
@@ -74,6 +74,8 @@ private:
QLabel *m_descriptionLabel;
QGroupBox *m_infoWidget;
QGridLayout *m_infoLayout;
+ ZLoadingWidget *m_loadingWidget;
+ QLabel *m_errorLabel;
// Data
iDescriptorDevice *m_device;
diff --git a/src/core/helpers/mounted_image_info_free.cpp b/src/core/helpers/mounted_image_info_free.cpp
new file mode 100644
index 0000000..06cb0b6
--- /dev/null
+++ b/src/core/helpers/mounted_image_info_free.cpp
@@ -0,0 +1,11 @@
+#include "../../iDescriptor.h"
+
+void mounted_image_info_free(MountedImageInfo &info)
+{
+ if (info.err) {
+ idevice_error_free(info.err);
+ }
+ if (info.signature) {
+ idevice_data_free(info.signature, info.signature_len);
+ }
+}
\ No newline at end of file
diff --git a/src/core/helpers/read_afc_file_to_byte_array.cpp b/src/core/helpers/read_afc_file_to_byte_array.cpp
index 3ab98d4..9739de7 100644
--- a/src/core/helpers/read_afc_file_to_byte_array.cpp
+++ b/src/core/helpers/read_afc_file_to_byte_array.cpp
@@ -18,75 +18,77 @@
*/
#include "../../iDescriptor.h"
+#include "../../servicemanager.h"
#include
#include
-QByteArray read_afc_file_to_byte_array(afc_client_t afcClient, const char *path)
+QByteArray read_afc_file_to_byte_array(const iDescriptorDevice *device,
+ const char *path)
{
- uint64_t fd_handle = 0;
- afc_error_t fd_err =
- afc_file_open(afcClient, path, AFC_FOPEN_RDONLY, &fd_handle);
+ AfcFileHandle *handle = nullptr;
+ IdeviceFfiError *err_open = // Use distinct variable name
+ ServiceManager::safeAfcFileOpen(device, path, AfcRdOnly, &handle);
- if (fd_err != AFC_E_SUCCESS) {
- qDebug() << "Could not open file" << path << "Error:" << fd_err;
+ if (err_open) {
+ qDebug() << "Could not open file" << path
+ << "Error:" << err_open->message;
+ idevice_error_free(err_open); // Free the error object
return QByteArray();
}
- // TODO:Maybe use afc_get_file_info_plist instead?
- char **info = NULL;
- afc_get_file_info(afcClient, path, &info);
- uint64_t fileSize = 0;
- if (info) {
- for (int i = 0; info[i]; i += 2) {
- if (strcmp(info[i], "st_size") == 0) {
- fileSize = std::stoull(info[i + 1]);
- break;
- }
- }
- afc_dictionary_free(info);
- }
+ AfcFileInfo info = {};
+ IdeviceFfiError *err_info = // Use distinct variable name
+ ServiceManager::safeAfcGetFileInfo(device, path, &info);
+ if (err_info) {
+ qDebug() << "Could not get file info for file" << path
+ << "Error:" << err_info->message;
+ idevice_error_free(err_info); // Free the error object
+ ServiceManager::safeAfcFileClose(device, handle); // Close handle
+ return QByteArray();
+ }
+ // Note: afc_file_info_free will be called later if the function returns
+ // successfully or when returning early after the file size check.
+
+ qDebug() << "File size of" << path << "is" << info.size;
+ size_t fileSize = info.size;
if (fileSize == 0) {
- afc_file_close(afcClient, fd_handle);
+ ServiceManager::safeAfcFileClose(device, handle);
+ afc_file_info_free(&info); // Free internal strings of info
return QByteArray();
}
QByteArray buffer;
- buffer.resize(fileSize);
+ buffer.reserve(fileSize);
- uint64_t totalBytesRead = 0;
- const uint32_t CHUNK_SIZE = 1024 * 1024; // Read in 1MB chunks
- char *p = buffer.data();
+ uint8_t *chunkData = nullptr;
+ size_t bytesRead = 0;
+ IdeviceFfiError *read_err = ServiceManager::safeAfcFileRead(
+ device, handle, &chunkData, fileSize, &bytesRead);
- while (totalBytesRead < fileSize) {
- uint32_t bytesToRead =
- std::min((uint64_t)CHUNK_SIZE, fileSize - totalBytesRead);
- uint32_t bytesReadThisChunk = 0;
- afc_error_t read_err =
- afc_file_read(afcClient, fd_handle, p + totalBytesRead, bytesToRead,
- &bytesReadThisChunk);
-
- if (read_err != AFC_E_SUCCESS) {
- qDebug() << "AFC Error: Read failed for file" << path
- << "Error:" << read_err;
- afc_file_close(afcClient, fd_handle);
- return QByteArray();
- }
-
- if (bytesReadThisChunk == 0) {
- // Premature end of file
- break;
- }
- totalBytesRead += bytesReadThisChunk;
+ if (read_err) {
+ qDebug() << "AFC Error: Read failed for file" << path
+ << "Error:" << read_err->message;
+ idevice_error_free(read_err);
+ ServiceManager::safeAfcFileClose(device, handle);
+ afc_file_info_free(&info); // Free internal strings of info
+ return QByteArray();
}
- afc_file_close(afcClient, fd_handle);
+ // Only append and free `chunkData` if `afc_file_read` was successful
+ buffer.append(reinterpret_cast(chunkData), bytesRead);
+ afc_file_read_data_free(chunkData,
+ bytesRead); // Free memory owned by Rust FFI
- if (totalBytesRead != fileSize) {
+ ServiceManager::safeAfcFileClose(device, handle);
+
+ if (bytesRead != fileSize) {
qDebug() << "AFC Error: Read mismatch for file" << path
- << "Read:" << totalBytesRead << "Expected:" << fileSize;
- return QByteArray(); // Read failed
+ << "Read:" << bytesRead << "Expected:" << fileSize;
+ afc_file_info_free(&info); // Free internal strings of info
+ return QByteArray(); // Read failed
}
+ afc_file_info_free(&info); // Free internal strings of info on success path
return buffer;
}
\ No newline at end of file
diff --git a/src/core/services/afc2_client_new.cpp b/src/core/services/afc2_client_new.cpp
deleted file mode 100644
index 06ee21f..0000000
--- a/src/core/services/afc2_client_new.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * iDescriptor: A free and open-source idevice management tool.
- *
- * Copyright (C) 2025 Uncore
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-#include "../../iDescriptor.h"
-#include
-#include
-#include
-#include
-
-afc_error_t afc2_client_new(idevice_t device, afc_client_t *afc)
-{
-
- lockdownd_service_descriptor_t service = NULL;
- // TODO: should free service ?
- lockdownd_client_t client = NULL;
-
- if (lockdownd_client_new_with_handshake(device, &client, APP_LABEL) !=
- LOCKDOWN_E_SUCCESS) {
- qDebug() << "Could not connect to lockdownd";
- return AFC_E_UNKNOWN_ERROR;
- }
- if (lockdownd_start_service(client, AFC2_SERVICE_NAME, &service) !=
- LOCKDOWN_E_SUCCESS) {
- qDebug() << "Could not start AFC service";
- lockdownd_client_free(client);
- return AFC_E_UNKNOWN_ERROR;
- }
-
- return afc_client_new(device, service, afc);
-
- // char **dirs = NULL;
- // if (afc_read_directory(afc, argv[1], &dirs) == AFC_E_SUCCESS) {
- // for (int i = 0; dirs[i]; i++) {
- // printf("Entry: %s\n", dirs[i]);
- // }
- // // free(dirs);
- // }
-}
\ No newline at end of file
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-afc2.cpp b/src/core/services/detect-afc2.cpp
index 79e832d..09c1b7b 100644
--- a/src/core/services/detect-afc2.cpp
+++ b/src/core/services/detect-afc2.cpp
@@ -17,4 +17,4 @@
* along with this program. If not, see .
*/
-// Detect AFC2 (Apple File Conduit 2) support
\ No newline at end of file
+// TODO:Detect AFC2 (Apple File Conduit 2) support
\ No newline at end of file
diff --git a/src/core/services/detect_has_been_jailbroken_before.cpp b/src/core/services/detect_has_been_jailbroken_before.cpp
index 02d4314..9d7ff4a 100644
--- a/src/core/services/detect_has_been_jailbroken_before.cpp
+++ b/src/core/services/detect_has_been_jailbroken_before.cpp
@@ -18,7 +18,6 @@
*/
#include "../../iDescriptor.h"
-#include
#include
#include
@@ -27,25 +26,29 @@ struct JailbreakDetectionResult {
std::vector found_folders;
};
-JailbreakDetectionResult detect_has_jailbroken_before(afc_client_t afc)
+// char *possible_jailbreak_paths[] = {
+// "/Applications/Cydia.app",
+// "/Library/MobileSubstrate/MobileSubstrate.dylib",
+// "/bin/bash",
+// "/usr/sbin/sshd",
+// "/etc/apt",
+// NULL
+// };
+
+JailbreakDetectionResult detect_has_jailbroken_before(AfcClientHandle *afc)
{
- std::vector jailbreak_folders = {".installed_palera1n",
- ".procursus_strapped"};
+ // std::vector jailbreak_folders = {".installed_palera1n",
+ // ".procursus_strapped"};
JailbreakDetectionResult result = {false, {}};
- char **dirs = NULL;
- if (afc_read_directory(afc, POSSIBLE_ROOT, &dirs) == AFC_E_SUCCESS) {
- for (char **dir = dirs; *dir != nullptr; ++dir) {
- std::string dirname = *dir;
- for (const auto &jb_folder : jailbreak_folders) {
- if (dirname == jb_folder) {
- result.found_folders.push_back(jb_folder);
- result.is_jailbroken = true;
- }
- }
- }
- }
- afc_dictionary_free(dirs);
+ // char **dirs = NULL;
+ // size_t count = 0;
+ // if (!afc_list_directory(afc, (std::string(POSSIBLE_ROOT) +
+ // "bin").c_str(),
+ // &dirs, &count)) {
+ // free(dirs);
+ // }
+ // afc_dictionary_free(dirs);
return result;
}
\ No newline at end of file
diff --git a/src/core/services/detect_jailbroken.cpp b/src/core/services/detect_jailbroken.cpp
index ff41ec9..788e219 100644
--- a/src/core/services/detect_jailbroken.cpp
+++ b/src/core/services/detect_jailbroken.cpp
@@ -18,29 +18,17 @@
*/
#include "../../iDescriptor.h"
-#include
-// char *possible_jailbreak_paths[] = {
-// "/Applications/Cydia.app",
-// "/Library/MobileSubstrate/MobileSubstrate.dylib",
-// "/bin/bash",
-// "/usr/sbin/sshd",
-// "/etc/apt",
-// NULL
-// };
+
#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;
+ if (!afc_list_directory(afc, (std::string(POSSIBLE_ROOT) + "bin").c_str(),
+ &dirs, &count)) {
+ free_directory_listing(dirs, count);
}
- afc_dictionary_free(dirs);
- return false;
+
+ return count > 0;
}
\ No newline at end of file
diff --git a/src/core/services/dnssd/dnssd_service.cpp b/src/core/services/dnssd/dnssd_service.cpp
index 05dcedb..1d615f3 100644
--- a/src/core/services/dnssd/dnssd_service.cpp
+++ b/src/core/services/dnssd/dnssd_service.cpp
@@ -174,6 +174,7 @@ void DNSSD_API DnssdService::resolveCallback(
pending.hostname = QString::fromUtf8(hosttarget);
pending.port = ntohs(port);
pending.interfaceIndex = interfaceIndex;
+ pending.macAddress = serviceName.split('@').first();
// Parse TXT records
if (txtLen > 0 && txtRecord) {
@@ -288,6 +289,7 @@ void DNSSD_API DnssdService::addrInfoCallback(
device.hostname = pending.hostname;
device.address = QString::fromUtf8(ip);
device.port = pending.port > 0 ? pending.port : 22; // Default to SSH port
+ device.macAddress = pending.macAddress;
qDebug() << "Resolved IP for Apple device:" << device.name << "at"
<< device.address << ":" << device.port;
diff --git a/src/core/services/dnssd/dnssd_service.h b/src/core/services/dnssd/dnssd_service.h
index 2bb0337..0818bba 100644
--- a/src/core/services/dnssd/dnssd_service.h
+++ b/src/core/services/dnssd/dnssd_service.h
@@ -88,6 +88,7 @@ private:
uint16_t port;
uint32_t interfaceIndex;
QMap txt;
+ QString macAddress;
};
QMap m_pendingDevices;
};
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..2afb964 100644
--- a/src/core/services/get_battery_info.cpp
+++ b/src/core/services/get_battery_info.cpp
@@ -20,35 +20,26 @@
#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(DiagnosticsRelay *diag_client, plist_t &diagnostics)
{
- diagnostics_relay_client_t diagnostics_client = nullptr;
- try {
+ qDebug() << "Fetching battery info via DiagnosticsRelay";
+ auto ioreg_result = diag_client->ioregistry(
+ IdeviceFFI::None, // current_plane
+ IdeviceFFI::None, // entry_name
+ IdeviceFFI::Some(std::string("IOPMPowerSource")) // entry_class
+ );
- if (diagnostics_relay_client_start_service(idevice, &diagnostics_client,
- nullptr) !=
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- qDebug() << "Failed to start diagnostics relay service.";
- return;
- }
+ if (!ioreg_result.is_ok()) {
+ qDebug() << "Failed to query IORegistry:"
+ << ioreg_result.unwrap_err().message.c_str();
+ return;
+ }
- if (diagnostics_relay_query_ioregistry_entry(
- diagnostics_client, nullptr, "IOPMPowerSource", &diagnostics) !=
- DIAGNOSTICS_RELAY_E_SUCCESS &&
- !diagnostics) {
-
- 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();
+ auto plist_opt = std::move(ioreg_result).unwrap();
+ if (plist_opt.is_some()) {
+ diagnostics = std::move(plist_opt).unwrap();
}
}
\ No newline at end of file
diff --git a/src/core/services/get_cable_info.cpp b/src/core/services/get_cable_info.cpp
index 68532ef..61dc781 100644
--- a/src/core/services/get_cable_info.cpp
+++ b/src/core/services/get_cable_info.cpp
@@ -18,51 +18,24 @@
*/
#include "../../iDescriptor.h"
-#include
-#include
-#include
-void get_cable_info(idevice_t device, plist_t &response)
+void _get_cable_info(const iDescriptorDevice *device, plist_t &response)
{
- lockdownd_client_t lockdown_client = NULL;
- diagnostics_relay_client_t diagnostics_client = NULL;
- lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
- lockdownd_service_descriptor_t service = NULL;
- int use_network = 0;
- if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(
- device, &lockdown_client, TOOL_NAME))) {
- idevice_free(device);
- printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
+ auto ioreg_result = device->diagRelay->ioregistry(
+ IdeviceFFI::None, // current_plane
+ IdeviceFFI::None, // entry_name
+ IdeviceFFI::Some(std::string("AppleTriStarBuiltIn")) // entry_class
+ );
+
+ if (!ioreg_result.is_ok()) {
+ qDebug() << "Failed to query IORegistry:"
+ << ioreg_result.unwrap_err().message.c_str();
+ return;
}
- /* attempt to use newer diagnostics service available on iOS 5 and later */
- ret = lockdownd_start_service(
- lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
- if (ret == LOCKDOWN_E_INVALID_SERVICE) {
- /* attempt to use older diagnostics service */
- ret = lockdownd_start_service(
- lockdown_client, "com.apple.iosdiagnostics.relay", &service);
+ auto plist_opt = std::move(ioreg_result).unwrap();
+ if (plist_opt.is_some()) {
+ response = std::move(plist_opt).unwrap();
}
- lockdownd_client_free(lockdown_client);
-
- if (ret != LOCKDOWN_E_SUCCESS) {
- idevice_free(device);
- printf("ERROR: Could not start diagnostics relay service: %s\n",
- lockdownd_strerror(ret));
- }
-
- if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
- if (diagnostics_relay_client_new(device, service,
- &diagnostics_client) !=
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- printf("ERROR: Could not connect to diagnostics_relay!\n");
- }
- }
-
- diagnostics_relay_error_t err = diagnostics_relay_query_ioregistry_entry(
- diagnostics_client, NULL, "AppleTriStarBuiltIn", &response);
-
- if (diagnostics_client)
- diagnostics_relay_client_free(diagnostics_client);
}
\ No newline at end of file
diff --git a/src/core/services/get_file_tree.cpp b/src/core/services/get_file_tree.cpp
index 2c7bba5..28afbb8 100644
--- a/src/core/services/get_file_tree.cpp
+++ b/src/core/services/get_file_tree.cpp
@@ -18,71 +18,109 @@
*/
#include "../../iDescriptor.h"
+#include "../../servicemanager.h"
#include
#include
-#include
-#include
#include
-AFCFileTree get_file_tree(afc_client_t afcClient, const std::string &path,
- bool checkDir)
+AFCFileTree get_file_tree(const iDescriptorDevice *device, bool checkDir,
+ const std::string &path,
+ std::optional altAfc)
{
-
+ qDebug() << "Getting file tree for path:" << QString::fromStdString(path);
AFCFileTree result;
result.currentPath = path;
+ result.success = false;
- char **dirs = NULL;
- if (afc_read_directory(afcClient, path.c_str(), &dirs) != AFC_E_SUCCESS) {
- result.success = false;
+ char **dirs = nullptr;
+ size_t count = 0;
+
+ // Use safe wrapper to read directory
+ IdeviceFfiError *err = ServiceManager::safeAfcReadDirectory(
+ device, path.c_str(), &dirs, count, altAfc);
+
+ if (err) {
+ qDebug() << "Failed to read directory:" << path.c_str()
+ << "Error:" << err->message << "Code:" << err->code;
+ idevice_error_free(err);
return result;
}
+ if (!dirs) {
+ result.success = true;
+ return result;
+ }
+
+ // Iterate through directory entries
for (int i = 0; dirs[i]; i++) {
+ // qDebug() << "Found entry:" << dirs[i];
std::string entryName = dirs[i];
if (entryName == "." || entryName == "..")
continue;
- char **info = NULL;
std::string fullPath = path;
if (fullPath.back() != '/')
fullPath += "/";
fullPath += entryName;
- bool isDir = false;
+
if (!checkDir) {
- isDir = false;
- } else if (afc_get_file_info(afcClient, fullPath.c_str(), &info) ==
- AFC_E_SUCCESS &&
- info) {
- if (entryName == "var") {
- qDebug() << "File info for var:" << info[0] << info[1]
- << info[2] << info[3] << info[4] << info[5];
- }
- for (int j = 0; info[j]; j += 2) {
- if (strcmp(info[j], "st_ifmt") == 0) {
- if (strcmp(info[j + 1], "S_IFDIR") == 0) {
- isDir = true;
- } else if (strcmp(info[j + 1], "S_IFLNK") == 0) {
- /*symlink*/
- char **dir_contents = NULL;
- if (afc_read_directory(afcClient, fullPath.c_str(),
- &dir_contents) ==
- AFC_E_SUCCESS) {
- isDir = true;
- if (dir_contents) {
- afc_dictionary_free(dir_contents);
- }
- }
- }
- break;
+ result.entries.push_back({entryName, false});
+ continue;
+ }
+
+ // Get file info using safe wrapper
+ AfcFileInfo info = {};
+ IdeviceFfiError *info_err = ServiceManager::safeAfcGetFileInfo(
+ device, fullPath.c_str(), &info, altAfc);
+
+ if (info_err) {
+ qDebug() << "Failed to get file info for:" << fullPath.c_str()
+ << "Error:" << info_err->message
+ << "Code:" << info_err->code;
+ }
+
+ bool isDir = false;
+ if (!info_err) {
+ // qDebug() << "Entry:" << entryName.c_str() << "Type:" <<
+ // info.st_ifmt
+ // << "Size:" << info.size;
+ if (strcmp(info.st_ifmt, "S_IFDIR") == 0) {
+ isDir = true;
+ } else if (strcmp(info.st_ifmt, "S_IFLNK") == 0) {
+ // Check if symlink points to a directory
+ char **dir_contents = nullptr;
+ size_t count = 0;
+ // FIXME: recursively call safeAfcGetFileInfo to figure out if
+ // it's a dir
+ IdeviceFfiError *link_err =
+ ServiceManager::safeAfcReadDirectory(
+ device, fullPath.c_str(), &dir_contents, count, altAfc);
+
+ if (!link_err) {
+ isDir = true;
+ free_directory_listing(dir_contents, count);
+ }
+
+ if (link_err) {
+ idevice_error_free(link_err);
}
}
- afc_dictionary_free(info);
+
+ afc_file_info_free(&info);
}
+
+ if (info_err) {
+ idevice_error_free(info_err);
+ }
+
result.entries.push_back({entryName, isDir});
}
+
+ // Free the directory list
if (dirs) {
- afc_dictionary_free(dirs);
+ free_directory_listing(dirs, count);
}
+
result.success = true;
return result;
}
\ No newline at end of file
diff --git a/src/core/services/get_mounted_image.cpp b/src/core/services/get_mounted_image.cpp
index a37221f..ff52f42 100644
--- a/src/core/services/get_mounted_image.cpp
+++ b/src/core/services/get_mounted_image.cpp
@@ -18,101 +18,30 @@
*/
#include "../../iDescriptor.h"
-#include
-#define _GNU_SOURCE 1
-#define __USE_GNU 1
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#ifndef _WIN32
-#include
-#endif
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#ifndef _WIN32
-#include
-#endif
-
-plist_t _get_mounted_image(const char *udid)
+MountedImageInfo _get_mounted_image(const iDescriptorDevice *device)
{
- mobile_image_mounter_client_t mim = NULL;
- lockdownd_client_t lckd = NULL;
- lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
- afc_client_t afc = NULL;
- lockdownd_service_descriptor_t service = NULL;
- idevice_t device = NULL;
-
- mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
- plist_t result = NULL;
- size_t sig_length = 0;
- const char *imagetype = "Developer";
-
- if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid,
-
- IDEVICE_LOOKUP_USBMUX)) {
- qDebug() << "ERROR: Could not create idevice!";
+ uint8_t *signature = NULL;
+ size_t signature_len = 0;
+ IdeviceFfiError *err = nullptr;
+ qDebug() << "_get_mounted_image";
+ if (err) {
+ qDebug() << "Failed to connect to image mounter:" << err->message;
goto leave;
}
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(
- device, &lckd, TOOL_NAME))) {
- qDebug() << "ERROR: Could not connect to lockdownd service!";
- goto leave;
+ err = image_mounter_lookup_image(device->imageMounter,
+ DISK_IMAGE_TYPE_DEVELOPER, &signature,
+ &signature_len);
+ if (err) {
+ qDebug() << "Failed to lookup image:" << err->message
+ << "Code:" << err->code;
}
- lockdownd_start_service(lckd, "com.apple.mobile.mobile_image_mounter",
- &service);
-
- if (!service || service->port == 0) {
- printf("ERROR: Could not start mobile_image_mounter service!\n");
- goto leave;
- }
-
- if (mobile_image_mounter_new(device, service, &mim) !=
- MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- printf("ERROR: Could not connect to mobile_image_mounter!\n");
- goto leave;
- }
-
- if (!service || service->port == 0) {
- qDebug() << "ERROR: Could not start mobile_image_mounter service!";
- goto leave;
- }
-
- // will sometimes return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the device
- // is locked - mostly on older devices
- err = mobile_image_mounter_lookup_image(mim, imagetype, &result);
-
leave:
- if (mim) {
- mobile_image_mounter_free(mim);
- }
- if (afc) {
- afc_client_free(afc);
- }
- if (lckd) {
- lockdownd_client_free(lckd);
- }
- if (device) {
- idevice_free(device);
- }
-
- return result;
-}
-
-// int main(){return 0;}
\ No newline at end of file
+ return {
+ .err = err,
+ .signature = signature,
+ .signature_len = signature_len,
+ };
+}
\ No newline at end of file
diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp
index 0062a21..6520e02 100644
--- a/src/core/services/init_device.cpp
+++ b/src/core/services/init_device.cpp
@@ -19,15 +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 "../../heartbeat.h"
#include
-#include
-#include
-#include
+#include
+#include
+#include
#include
+#include
+#include
std::string safeGetXML(const char *key, pugi::xml_node dict)
{
@@ -150,7 +154,8 @@ void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d)
}
DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
- afc_client_t &afcClient,
+ AfcClientHandle *afcClient,
+ DiagnosticsRelay *diagRelay,
iDescriptorInitDeviceResult &result)
{
pugi::xml_node dict = doc.child("plist").child("dict");
@@ -194,29 +199,39 @@ 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('.');
- int major = (parts.length() > 0) ? parts[0].toInt() : 0;
- int minor = (parts.length() > 1) ? parts[1].toInt() : 0;
- int patch = (parts.length() > 2) ? parts[2].toInt() : 0;
+ unsigned int major = (parts.length() > 0) ? parts[0].toInt() : 0;
+ unsigned int minor = (parts.length() > 1) ? parts[1].toInt() : 0;
+ unsigned int patch = (parts.length() > 2) ? parts[2].toInt() : 0;
- d.parsedDeviceVersion = IDEVICE_DEVICE_VERSION(major, minor, patch);
+ d.parsedDeviceVersion =
+ DeviceVersion{.major = major, .minor = minor, .patch = patch};
/*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 +241,21 @@ 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]));
+ // FIXME: it's too slow on older devices?
+ AfcDeviceInfo *info = new AfcDeviceInfo();
+ qDebug() << "afc_get_device_info...";
+ 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 +304,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(diagRelay, 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"];
@@ -300,7 +323,7 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
}
bool newerThaniPhone8 =
- is_product_type_newer(rawProductType, std::string("iPhone8,1"));
+ iDescriptor::Utils::isProductTypeNewer(rawProductType, "iPhone8,1");
uint64_t cycleCount = ioreg["BatteryData"]["CycleCount"].getUInt();
@@ -329,6 +352,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 +364,280 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc,
}
}
-iDescriptorInitDeviceResult init_idescriptor_device(const char *udid)
+iDescriptorInitDeviceResult
+init_idescriptor_device(const QString &udid,
+ const WirelessInitArgs &wirelessArgs)
{
- qDebug() << "Initializing iDescriptor device with UDID: "
- << QString::fromUtf8(udid);
+ const bool isWireless =
+ !wirelessArgs.ip.isEmpty() && !wirelessArgs.pairing_file.isEmpty();
+ 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;
+ HeartbeatClientHandle *heartbeat = nullptr;
+ HeartbeatThread *heartbeatThread = nullptr;
+ ImageMounterHandle *image_mounter = nullptr;
+ DiagnosticsRelayClientHandle *diagnostics_relay = nullptr;
+ LocationSimulationHandle *location_simulation = nullptr;
+ plist_t val = nullptr;
- idevice_error_t ret =
- idevice_new_with_options(&device, udid, IDEVICE_LOOKUP_USBMUX);
+ 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
+ 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 (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);
+ inet_pton(AF_INET, wirelessArgs.ip.toUtf8().constData(),
+ &addr_in.sin_addr);
+ qDebug() << "Reading pairing file from" << wirelessArgs.pairing_file
+ << "for udid" << udid;
+ err = idevice_pairing_file_read(
+ wirelessArgs.pairing_file.toUtf8().constData(), &pairing_file);
+ if (err) {
+ qDebug() << "Failed to read pairing file";
+ 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;
- }
+ err = idevice_tcp_provider_new(
+ (const idevice_sockaddr *)&addr_in,
+ const_cast(pairing_file), APP_LABEL,
+ &provider);
+ if (err) {
+ qDebug() << "Failed to create wireless provider";
+ goto cleanup;
+ }
+ err = heartbeat_connect(provider, &heartbeat);
+ if (err) {
+ qDebug() << "Failed to start Heartbeat service";
+ goto cleanup;
+ }
+ // udid is mac address here for wireless
+ heartbeatThread = new HeartbeatThread(heartbeat, udid);
+ heartbeatThread->start();
- if (afc_client_new(device, lockdownService, &afcClient) != AFC_E_SUCCESS) {
- qDebug() << "Failed to create AFC client.";
+ while (!heartbeatThread->initialCompleted()) {
+ sleep(1);
+ }
- 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;
} 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
+ err = lockdownd_connect(provider, &lockdown);
+ if (err) {
+ qDebug() << "Failed to connect to lockdown";
+ 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;
+ }
+
+ if (err) {
+ qDebug() << "Failed to connect to Heartbeat client";
+ goto cleanup;
+ }
+
+ err = afc_client_connect(provider, &afc_client);
+ if (err) {
+ qDebug() << "Failed to create AFC client";
+ goto cleanup;
+ }
+
+ err = image_mounter_connect(provider, &image_mounter);
+ if (err) {
+ qDebug() << "Failed to create Image Mounter client";
+ goto cleanup;
+ }
+
+ err = diagnostics_relay_client_connect(provider, &diagnostics_relay);
+
+ if (err) {
+ qDebug() << "Failed to create Diagnostics Relay client";
+ goto cleanup;
+ }
+
+ err = afc2_client_connect(provider, &afc2_client);
+ if (err) {
+ qDebug() << "Failed to create AFC2 client";
+ // dont cleanup here, afc2 is optional
+ }
+
+ // FIXME: will probably not work on iOS 17 and above
+ // requires dev image disk
+ // err = location_simulation_connect(provider, &location_simulation);
+ // if (err) {
+ // qDebug() << "Failed to create Location Simulation client";
+ // goto cleanup;
+ // }
+ get_device_info_xml(udid.toUtf8().constData(), lockdown, infoXml);
+
+ lockdownd_get_value(lockdown, "EnableWifiConnections",
+ "com.apple.mobile.wireless_lockdown", &val);
+ if (val)
+ plist_print(val);
+
+ result.provider = 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;
+ // TODO:remove, not really required to get some stuff going so it can be
+ // optional
+ result.imageMounter = image_mounter;
+ result.diagRelay = std::make_shared(
+ DiagnosticsRelay::adopt(diagnostics_relay));
+ result.locationSimulation = location_simulation;
+ result.heartbeatThread = heartbeatThread;
+ // TODO cache pairing file path
+ result.deviceInfo.isWireless = isWireless;
+ fullDeviceInfo(infoXml, afc_client, result.diagRelay.get(), result);
+ ::QObject::connect(heartbeatThread, &HeartbeatThread::heartbeatFailed,
+ AppContext::sharedInstance(),
+ &AppContext::heartbeatFailed);
+ ::QObject::connect(heartbeatThread, &HeartbeatThread::heartbeatThreadExited,
+ AppContext::sharedInstance(), &AppContext::removeDevice);
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/core/services/install_ipa.cpp b/src/core/services/install_ipa.cpp
index 01a2765..761b416 100644
--- a/src/core/services/install_ipa.cpp
+++ b/src/core/services/install_ipa.cpp
@@ -17,538 +17,95 @@
* along with this program. If not, see .
*/
-#ifdef HAVE_CONFIG_H
-#include
-#endif
-#include
-#define _GNU_SOURCE 1
-#define __USE_GNU 1
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include "../../iDescriptor.h"
-#ifdef HAVE_UNISTD_H
-#include
-#endif
-#ifndef WIN32
-#include
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-
-#include
-
-#include
-
-#ifdef WIN32
-#include
-#define wait_ms(x) Sleep(x)
-#else
-#define wait_ms(x) \
- { \
- struct timespec ts; \
- ts.tv_sec = 0; \
- ts.tv_nsec = x * 1000000; \
- nanosleep(&ts, NULL); \
- }
-#endif
-
-#define ITUNES_METADATA_PLIST_FILENAME "iTunesMetadata.plist"
-
-const char PKG_PATH[] = "PublicStaging";
-
-struct install_status_data {
- int command_completed;
- int err_occurred;
- char *last_status;
-};
-
-static void status_cb(plist_t command, plist_t status, void *user_data)
+IdeviceFfiError *_install_IPA(const iDescriptorDevice *device,
+ const char *filePath, const char *filename)
{
- struct install_status_data *isd = (struct install_status_data *)user_data;
- if (command && status) {
- char *command_name = NULL;
- instproxy_command_get_name(command, &command_name);
+ IdeviceFfiError *err = nullptr;
+ InstallationProxyClientHandle *instproxy_client = NULL;
+ AfcFileHandle *file = NULL;
+ std::string dest_path_str = "/PublicStaging/" + std::string(filename);
+ AfcFileInfo info = {};
+ uint8_t *data = NULL;
+ size_t length = 0;
- /* get status */
- char *status_name = NULL;
- instproxy_status_get_name(status, &status_name);
+ qDebug() << "Uploading " << filePath << " to " << dest_path_str.c_str()
+ << "...";
- if (status_name) {
- if (!strcmp(status_name, "Complete")) {
- isd->command_completed = 1;
- }
+ err = afc_get_file_info(device->afcClient, "/PublicStaging", &info);
+ // -33 /* No such file or directory */
+ if (err != NULL && err->code == -33) {
+ qDebug() << "/PublicStaging does not exist, creating...";
+ err = afc_make_directory(device->afcClient, "/PublicStaging");
+ if (err != NULL) {
+ qDebug() << "Failed to create /PublicStaging: [" << err->code
+ << "] " << err->message;
+ goto cleanup;
}
-
- /* get error if any */
- char *error_name = NULL;
- char *error_description = NULL;
- uint64_t error_code = 0;
- instproxy_status_get_error(status, &error_name, &error_description,
- &error_code);
-
- /* output/handling */
- if (!error_name) {
- if (status_name) {
- /* get progress if any */
- int percent = -1;
- instproxy_status_get_percent_complete(status, &percent);
-
- if (isd->last_status &&
- (strcmp(isd->last_status, status_name))) {
- printf("\n");
- }
-
- if (percent >= 0) {
- printf("\r%s: %s (%d%%)", command_name, status_name,
- percent);
- } else {
- printf("\r%s: %s", command_name, status_name);
- }
- if (isd->command_completed) {
- printf("\n");
- }
- }
- } else {
- /* report error to the user */
- if (error_description)
- fprintf(stderr,
- "ERROR: %s failed. Got error \"%s\" with code "
- "0x%08" PRIx64 ": %s\n",
- command_name, error_name, error_code,
- error_description ? error_description : "N/A");
- else
- fprintf(stderr, "ERROR: %s failed. Got error \"%s\".\n",
- command_name, error_name);
- isd->err_occurred = 1;
- }
-
- /* clean up */
- free(error_name);
- free(error_description);
-
- free(isd->last_status);
- isd->last_status = status_name;
-
- free(command_name);
- command_name = NULL;
- } else {
- fprintf(stderr, "ERROR: %s was called with invalid arguments!\n",
- __func__);
- }
-}
-
-static int zip_get_contents(struct zip *zf, const char *filename,
- int locate_flags, char **buffer, uint32_t *len)
-{
- struct zip_stat zs;
- struct zip_file *zfile;
- int zindex = zip_name_locate(zf, filename, locate_flags);
-
- *buffer = NULL;
- *len = 0;
-
- if (zindex < 0) {
- return -1;
+ qDebug() << "/PublicStaging created successfully";
+ } else if (err != NULL) {
+ qDebug() << "Failed to get info for /PublicStaging: [" << err->code
+ << "] " << err->message;
+ goto cleanup;
}
- zip_stat_init(&zs);
-
- if (zip_stat_index(zf, zindex, 0, &zs) != 0) {
- fprintf(stderr, "ERROR: zip_stat_index '%s' failed!\n", filename);
- return -2;
+ if (!read_file(filePath, &data, &length)) {
+ err = new IdeviceFfiError{-1, "Failed to read IPA file"};
+ goto cleanup;
}
- if (zs.size > 10485760) {
- fprintf(stderr, "ERROR: file '%s' is too large!\n", filename);
- return -3;
+ // todo should we use from service manager safe afc functions ?
+ err = afc_file_open(device->afcClient, dest_path_str.c_str(), AfcWrOnly,
+ &file);
+ if (err != NULL) {
+ qDebug() << "Failed to open destination file: [" << err->code << "] "
+ << err->message;
+ goto cleanup;
}
- zfile = zip_fopen_index(zf, zindex, 0);
- if (!zfile) {
- fprintf(stderr, "ERROR: zip_fopen '%s' failed!\n", filename);
- return -4;
+ err = afc_file_write(file, data, length);
+
+ if (err != NULL) {
+ qDebug() << "Failed to write file: [" << err->code << "] "
+ << err->message;
+ goto cleanup;
}
- *buffer = (char *)malloc(zs.size);
- if (zs.size > LLONG_MAX ||
- zip_fread(zfile, *buffer, zs.size) != (zip_int64_t)zs.size) {
- fprintf(stderr, "ERROR: zip_fread %" PRIu64 " bytes from '%s'\n",
- (uint64_t)zs.size, filename);
- free(*buffer);
- *buffer = NULL;
- zip_fclose(zfile);
- return -5;
- }
- *len = zs.size;
- zip_fclose(zfile);
- return 0;
-}
+ qDebug() << "Upload completed successfully";
-static int zip_get_app_directory(struct zip *zf, char **path)
-{
- zip_int64_t i = 0;
- zip_int64_t c = (zip_int64_t)zip_get_num_entries(zf, 0);
- int len = 0;
- const char *name = NULL;
-
- /* look through all filenames in the archive */
- do {
- /* get filename at current index */
- name = zip_get_name(zf, i++, 0);
- if (name != NULL) {
- /* check if we have a "Payload/.../" name */
- len = strlen(name);
- if (!strncmp(name, "Payload/", 8) && (len > 8)) {
- /* skip hidden files */
- if (name[8] == '.')
- continue;
-
- /* locate the second directory delimiter */
- const char *p = name + 8;
- do {
- if (*p == '/') {
- break;
- }
- } while (p++ != NULL);
-
- /* try next entry if not found */
- if (p == NULL)
- continue;
-
- len = p - name + 1;
-
- /* make sure app directory endwith .app */
- if (len < 12 || strncmp(p - 4, ".app", 4)) {
- continue;
- }
-
- if (path != NULL) {
- free(*path);
- *path = NULL;
- }
-
- /* allocate and copy filename */
- *path = (char *)malloc(len + 1);
- strncpy(*path, name, len);
-
- /* add terminating null character */
- char *t = *path + len;
- *t = '\0';
- break;
- }
- }
- } while (i < c);
-
- if (*path == NULL) {
- return -1;
+ err = installation_proxy_connect(device->provider, &instproxy_client);
+ if (err != NULL) {
+ qDebug() << "Failed to connect to installation proxy:" << err->message
+ << "Code:" << err->code;
+ goto cleanup;
}
- return 0;
-}
-
-static int afc_upload_file(afc_client_t afc, const char *filename,
- const char *dstfn)
-{
- FILE *f = NULL;
- uint64_t af = 0;
- char buf[1048576];
-
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "fopen: %s: %s\n", filename, strerror(errno));
- return -1;
- }
-
- if ((afc_file_open(afc, dstfn, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS) ||
- !af) {
- fclose(f);
- fprintf(stderr, "afc_file_open on '%s' failed!\n", dstfn);
- return -1;
- }
-
- size_t amount = 0;
- do {
- amount = fread(buf, 1, sizeof(buf), f);
- if (amount > 0) {
- uint32_t written, total = 0;
- while (total < amount) {
- written = 0;
- afc_error_t aerr =
- afc_file_write(afc, af, buf, amount, &written);
- if (aerr != AFC_E_SUCCESS) {
- fprintf(stderr, "AFC Write error: %d\n", aerr);
- break;
- }
- total += written;
- }
- if (total != amount) {
- fprintf(stderr, "Error: wrote only %u of %u\n", total,
- (uint32_t)amount);
- afc_file_close(afc, af);
- fclose(f);
- return -1;
- }
- }
- } while (amount > 0);
-
- afc_file_close(afc, af);
- fclose(f);
-
- return 0;
-}
-
-instproxy_error_t install_IPA(idevice_t device, afc_client_t afc,
- const char *filePath)
-{
- lockdownd_client_t client = NULL;
- instproxy_client_t ipc = NULL;
- lockdownd_service_descriptor_t service = NULL;
- instproxy_error_t err = INSTPROXY_E_UNKNOWN_ERROR;
- char *bundleidentifier = NULL;
- struct install_status_data status_data = {0, 0, NULL};
- plist_t sinf = NULL;
- plist_t meta = NULL;
- char *pkgname = NULL;
- struct stat fst;
- char **strs = NULL;
- plist_t client_opts = instproxy_client_options_new();
- char *zbuf = NULL;
- uint32_t len = 0;
- plist_t meta_dict = NULL;
- int errp = 0;
- struct zip *zf = zip_open(filePath, 0, &errp);
- plist_t info = NULL;
- char *filename = NULL;
- char *app_directory_name = NULL;
- char *bundleexecutable = NULL;
- plist_t bname = NULL;
- char *sinfname = NULL;
-
- if (!device || !filePath || !afc) {
- fprintf(stderr, "ERROR: Invalid arguments passed to install_IPA.\n");
- return INSTPROXY_E_INVALID_ARG;
- }
-
- lockdownd_error_t lerr = lockdownd_client_new_with_handshake(
- device, &client, "ideviceinstaller");
- if (lerr != LOCKDOWN_E_SUCCESS) {
- fprintf(stderr, "Could not connect to lockdownd: %s. Exiting.\n",
- lockdownd_strerror(lerr));
- return INSTPROXY_E_OP_FAILED;
- }
-
- lerr = lockdownd_start_service(
- client, "com.apple.mobile.installation_proxy", &service);
- if (lerr != LOCKDOWN_E_SUCCESS) {
- fprintf(stderr,
- "Could not start com.apple.mobile.installation_proxy: %s\n",
- lockdownd_strerror(lerr));
- lockdownd_client_free(client);
- return INSTPROXY_E_OP_FAILED;
- }
-
- err = instproxy_client_new(device, service, &ipc);
- if (service) {
- lockdownd_service_descriptor_free(service);
- service = NULL;
- }
-
- if (err != INSTPROXY_E_SUCCESS) {
- fprintf(stderr, "Could not connect to installation_proxy!\n");
- lockdownd_client_free(client);
- return err;
- }
-
- setbuf(stdout, NULL);
-
- if (stat(filePath, &fst) != 0) {
- fprintf(stderr, "ERROR: stat: %s: %s\n", filePath, strerror(errno));
- err = INSTPROXY_E_INVALID_ARG;
- goto leave_cleanup;
- }
-
- if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) {
- if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) {
- fprintf(stderr,
- "WARNING: Could not create directory '%s' on device!\n",
- PKG_PATH);
- }
- }
- if (strs) {
- int i = 0;
- while (strs[i]) {
- free(strs[i]);
- i++;
- }
- free(strs);
- }
-
- if (!zf) {
- fprintf(stderr, "ERROR: zip_open: %s: %d\n", filePath, errp);
- err = INSTPROXY_E_INVALID_ARG;
- goto leave_cleanup;
- }
-
- /* extract iTunesMetadata.plist from package */
- if (zip_get_contents(zf, ITUNES_METADATA_PLIST_FILENAME, 0, &zbuf, &len) ==
- 0) {
- meta = plist_new_data(zbuf, len);
- plist_from_memory(zbuf, len, &meta_dict, NULL);
- }
- if (!meta_dict) {
- plist_free(meta);
- meta = NULL;
- fprintf(stderr, "WARNING: could not locate %s in archive!\n",
- ITUNES_METADATA_PLIST_FILENAME);
- }
- free(zbuf);
-
- /* determine .app directory in archive */
- zbuf = NULL;
- len = 0;
-
- if (zip_get_app_directory(zf, &app_directory_name)) {
- fprintf(stderr, "ERROR: Unable to locate .app directory in archive. "
- "Make sure it is inside a 'Payload' directory.\n");
- err = INSTPROXY_E_INVALID_ARG;
- goto zip_cleanup;
- }
-
- /* construct full filename to Info.plist */
- filename = (char *)malloc(strlen(app_directory_name) + 10 + 1);
- strcpy(filename, app_directory_name);
- free(app_directory_name);
- app_directory_name = NULL;
- strcat(filename, "Info.plist");
-
- if (zip_get_contents(zf, filename, 0, &zbuf, &len) < 0) {
- fprintf(stderr, "WARNING: could not locate %s in archive!\n", filename);
- free(filename);
- err = INSTPROXY_E_INVALID_ARG;
- goto zip_cleanup;
- }
- free(filename);
- plist_from_memory(zbuf, len, &info, NULL);
- free(zbuf);
-
- if (!info) {
- fprintf(stderr, "Could not parse Info.plist!\n");
- err = INSTPROXY_E_INVALID_ARG;
- goto zip_cleanup;
- }
-
- bname = plist_dict_get_item(info, "CFBundleExecutable");
- if (bname) {
- plist_get_string_val(bname, &bundleexecutable);
- }
-
- bname = plist_dict_get_item(info, "CFBundleIdentifier");
- if (bname) {
- plist_get_string_val(bname, &bundleidentifier);
- }
- plist_free(info);
- info = NULL;
-
- if (!bundleexecutable) {
- fprintf(stderr, "Could not determine value for CFBundleExecutable!\n");
- err = INSTPROXY_E_INVALID_ARG;
- goto zip_cleanup;
- }
-
- if (asprintf(&sinfname, "Payload/%s.app/SC_Info/%s.sinf", bundleexecutable,
- bundleexecutable) < 0) {
- fprintf(stderr, "Out of memory!?\n");
- err = INSTPROXY_E_UNKNOWN_ERROR;
- goto zip_cleanup;
- }
- free(bundleexecutable);
-
- /* extract .sinf from package */
- zbuf = NULL;
- len = 0;
- if (zip_get_contents(zf, sinfname, 0, &zbuf, &len) == 0) {
- sinf = plist_new_data(zbuf, len);
- } else {
- fprintf(stderr, "WARNING: could not locate %s in archive!\n", sinfname);
- }
- free(sinfname);
- free(zbuf);
-
- /* copy archive to device */
- pkgname = NULL;
- if (asprintf(&pkgname, "%s/%s", PKG_PATH, bundleidentifier) < 0) {
- fprintf(stderr, "Out of memory!?\n");
- err = INSTPROXY_E_UNKNOWN_ERROR;
- goto zip_cleanup;
- }
-
- printf("Copying '%s' to device... ", filePath);
-
- if (afc_upload_file(afc, filePath, pkgname) < 0) {
- printf("FAILED\n");
- free(pkgname);
- err = INSTPROXY_E_OP_FAILED;
- goto zip_cleanup;
- }
-
- printf("DONE.\n");
-
- if (bundleidentifier) {
- instproxy_client_options_add(client_opts, "CFBundleIdentifier",
- bundleidentifier, NULL);
- }
- if (sinf) {
- instproxy_client_options_add(client_opts, "ApplicationSINF", sinf,
+ qDebug() << "Installing the ipa on idevice, path on device is "
+ << dest_path_str.c_str();
+ err = installation_proxy_install(instproxy_client, dest_path_str.c_str(),
NULL);
- }
- if (meta) {
- instproxy_client_options_add(client_opts, "iTunesMetadata", meta, NULL);
- }
-
-zip_cleanup:
- if (zf) {
- zip_unchange_all(zf);
- zip_close(zf);
- }
- if (err != INSTPROXY_E_SUCCESS) {
- goto leave_cleanup;
- }
-
- /* perform installation */
- printf("Installing '%s'\n", bundleidentifier);
- instproxy_install(ipc, pkgname, client_opts, status_cb, &status_data);
-
- instproxy_client_options_free(client_opts);
- free(pkgname);
-
- while (!status_data.command_completed && !status_data.err_occurred) {
- wait_ms(50);
- }
-
- if (status_data.err_occurred) {
- err = INSTPROXY_E_OP_FAILED;
+ if (err != NULL) {
+ qDebug() << "Installation failed: [" << err->code << "] "
+ << err->message;
+ goto cleanup;
} else {
- err = INSTPROXY_E_SUCCESS;
+ qDebug() << "Installation completed successfully";
}
-leave_cleanup:
- instproxy_client_free(ipc);
- lockdownd_client_free(client);
- free(bundleidentifier);
- free(status_data.last_status);
+cleanup:
+
+ if (data) {
+ free(data);
+ }
+
+ if (file) {
+ afc_file_close(file);
+ }
+
+ if (instproxy_client) {
+ installation_proxy_client_free(instproxy_client);
+ }
return err;
-}
\ No newline at end of file
+}
diff --git a/src/core/services/mount_dev_image.cpp b/src/core/services/mount_dev_image.cpp
index 5b9a9b3..542d994 100644
--- a/src/core/services/mount_dev_image.cpp
+++ b/src/core/services/mount_dev_image.cpp
@@ -19,596 +19,61 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define _GNU_SOURCE 1
#include "../../iDescriptor.h"
-#include
-#define __USE_GNU 1
-#include
-#include
-#include
-#include
#include
-#include
-#include
-#include
-#include
-#ifndef _WIN32
-#include
-#endif
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#ifndef _WIN32
-#include
-#endif
+#include
-typedef enum {
- DISK_IMAGE_UPLOAD_TYPE_AFC,
- DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE
-} disk_image_upload_type_t;
-
-static const char *imagetype = NULL;
-
-static const char PKG_PATH[] = "PublicStaging";
-static const char PATH_PREFIX[] = "/private/var/mobile/Media";
-
-static ssize_t mim_upload_cb(void *buf, size_t size, void *userdata)
+// Failed to mount developer image: [-21] DeviceLockedMount image result: false
+IdeviceFfiError *mount_dev_image(const iDescriptorDevice *device,
+ const char *image_file,
+ const char *signature_file)
{
- return fread(buf, 1, size, (FILE *)userdata);
-}
-// extend the mobile_image_mounter_error_t type and return sucess if there is
-// already a disk image
-mobile_image_mounter_error_t mount_dev_image(idevice_t device,
- unsigned int device_version,
- const char *image_dir_path)
-{
- mobile_image_mounter_client_t mim = NULL;
- int res = -1;
- size_t image_size = 0;
- lockdownd_client_t lckd = NULL;
- lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
- afc_client_t afc = NULL;
- lockdownd_service_descriptor_t service = NULL;
- char *image_path = NULL;
- char *image_sig_path = NULL;
- FILE *f = NULL;
- unsigned char *sig = NULL;
- plist_t mount_options = NULL;
- char *targetname = NULL;
- char *mountname = NULL;
- disk_image_upload_type_t disk_image_upload_type =
- DISK_IMAGE_UPLOAD_TYPE_AFC;
- mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
- plist_t result = NULL;
- size_t sig_length = 0;
-
- if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(
- device, &lckd, TOOL_NAME))) {
- qDebug() << "ERROR: Could not connect to lockdownd service!";
- res = -1;
- goto leave;
+ if (!device || !device->provider || !device->imageMounter) {
+ qDebug()
+ << "Error: Invalid device or provider passed to mount_dev_image";
+ return new IdeviceFfiError{// FIXME: whats the code ?
+ .code = -1,
+ .message = "Invalid device or provider"};
}
- if (device_version >= IDEVICE_DEVICE_VERSION(7, 0, 0)) {
- disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE;
+ size_t image_len = 0;
+ size_t signature_len = 0;
+ uint8_t *image_data = nullptr;
+ uint8_t *signature_data = nullptr;
+ IdeviceFfiError *err = nullptr;
+
+ if (err) {
+ goto cleanup;
}
- if (disk_image_upload_type == DISK_IMAGE_UPLOAD_TYPE_AFC) {
- lockdownd_error_t lerr =
- lockdownd_start_service(lckd, "com.apple.afc", &service);
- if (lerr != LOCKDOWN_E_SUCCESS) {
- qDebug() << "ERROR: Could not start AFC service!"
- << lockdownd_strerror(lerr) << "(" << lerr << ")";
- res = -1;
- goto leave;
- }
-
- afc_error_t rafc = afc_client_new(device, service, &afc);
- if (rafc != AFC_E_SUCCESS) {
- qDebug() << "ERROR: Could not connect to AFC!" << afc_strerror(rafc)
- << "(" << rafc << ")";
- res = -1;
- goto leave;
- }
- lockdownd_service_descriptor_free(service);
- service = NULL;
- }
-
- if (asprintf(&image_path, "%s/DeveloperDiskImage.dmg", image_dir_path) <
- 0) {
- qDebug() << "Out of memory constructing image path!";
- res = -1;
- goto leave;
- }
-
- if (asprintf(&image_sig_path, "%s/DeveloperDiskImage.dmg.signature",
- image_dir_path) < 0) {
- qDebug() << "Out of memory constructing signature path!";
- res = -1;
- goto leave;
- }
-
- qDebug() << "Using image:" << image_path;
- qDebug() << "Using signature:" << image_sig_path;
-
- if (device_version >= IDEVICE_DEVICE_VERSION(16, 0, 0)) {
- uint8_t dev_mode_status = 0;
- plist_t val = NULL;
- ldret = lockdownd_get_value(lckd, "com.apple.security.mac.amfi",
- "DeveloperModeStatus", &val);
- if (ldret == LOCKDOWN_E_SUCCESS) {
- plist_get_bool_val(val, &dev_mode_status);
- plist_free(val);
- }
- if (!dev_mode_status) {
- qDebug() << "ERROR: You have to enable Developer Mode on the given "
- "device in order to allowing mounting a developer disk "
- "image.";
- res = -1;
- goto leave;
- }
- }
-
- lockdownd_start_service(lckd, "com.apple.mobile.mobile_image_mounter",
- &service);
-
- if (!service || service->port == 0) {
- qDebug() << "ERROR: Could not start mobile_image_mounter service!";
- res = -1;
- goto leave;
- }
-
- if (mobile_image_mounter_new(device, service, &mim) !=
- MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- qDebug() << "ERROR: Could not connect to mobile_image_mounter!";
- res = -1;
- goto leave;
- }
- lockdownd_service_descriptor_free(service);
- service = NULL;
-
- struct stat fst;
- if (stat(image_path, &fst) != 0) {
- qDebug() << "ERROR: stat:" << image_path << ":" << strerror(errno);
- res = -1;
- goto leave;
- }
- image_size = fst.st_size;
- if (device_version < IDEVICE_DEVICE_VERSION(17, 0, 0) &&
- stat(image_sig_path, &fst) != 0) {
- qDebug() << "ERROR: stat:" << image_sig_path << ":" << strerror(errno);
- res = -1;
- goto leave;
- }
-
- if (device_version < IDEVICE_DEVICE_VERSION(17, 0, 0)) {
- f = fopen(image_sig_path, "rb");
- if (!f) {
- qDebug() << "Error opening signature file" << image_sig_path << ":"
- << strerror(errno);
- res = -1;
- goto leave;
- }
- if (fstat(fileno(f), &fst) != 0) {
- qDebug() << "Error: fstat:" << strerror(errno);
- res = -1;
- goto leave;
- }
- sig = (unsigned char *)malloc(fst.st_size);
- sig_length = fread(sig, 1, fst.st_size, f);
- fclose(f);
- f = NULL;
- if (sig_length == 0) {
- qDebug() << "Could not read signature from file" << image_sig_path;
- res = -1;
- goto leave;
- }
-
- f = fopen(image_path, "rb");
- if (!f) {
- qDebug() << "Error opening image file" << image_path << ":"
- << strerror(errno);
- res = -1;
- goto leave;
- }
+ if (!read_file(image_file, &image_data, &image_len)) {
+ err = new IdeviceFfiError{.code = -1,
+ .message = "Failed to read image file"};
+ goto cleanup;
+ } else if (!read_file(signature_file, &signature_data, &signature_len)) {
+ err = new IdeviceFfiError{.code = -1,
+ .message = "Failed to read signature file"};
+ goto cleanup;
} else {
- char *build_manifest_path =
- string_build_path(image_path, "BuildManifest.plist", NULL);
- plist_t build_manifest = NULL;
- if (plist_read_from_file(build_manifest_path, &build_manifest, NULL) !=
- 0) {
- free(build_manifest_path);
- build_manifest_path = string_build_path(
- image_path, "Restore", "BuildManifest.plist", NULL);
- if (plist_read_from_file(build_manifest_path, &build_manifest,
- NULL) == 0) {
- char *image_path_new =
- string_build_path(image_path, "Restore", NULL);
- free(image_path);
- image_path = image_path_new;
- }
- }
- if (!build_manifest) {
- qDebug() << "Error: Could not locate BuildManifest.plist inside "
- "given disk image path!";
- res = -1;
- goto leave;
- }
-
- plist_t identifiers = NULL;
- mobile_image_mounter_error_t merr =
- mobile_image_mounter_query_personalization_identifiers(
- mim, NULL, &identifiers);
- if (merr != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- qDebug() << "Failed to query personalization identifiers:" << merr;
- res = -1;
- goto leave;
- }
-
- unsigned int board_id = plist_dict_get_uint(identifiers, "BoardId");
- unsigned int chip_id = plist_dict_get_uint(identifiers, "ChipID");
-
- plist_t build_identities =
- plist_dict_get_item(build_manifest, "BuildIdentities");
- plist_array_iter iter;
- plist_array_new_iter(build_identities, &iter);
- plist_t item = NULL;
- plist_t build_identity = NULL;
- do {
- plist_array_next_item(build_identities, iter, &item);
- if (!item) {
- break;
- }
- unsigned int bi_board_id =
- (unsigned int)plist_dict_get_uint(item, "ApBoardID");
- unsigned int bi_chip_id =
- (unsigned int)plist_dict_get_uint(item, "ApChipID");
- if (bi_chip_id == chip_id && bi_board_id == board_id) {
- build_identity = item;
- break;
- }
- } while (item);
- plist_mem_free(iter);
- if (!build_identity) {
- qDebug() << "Error: The given disk image is not compatible with "
- "the current device.";
- res = -1;
- goto leave;
- }
- plist_t p_tc_path =
- plist_access_path(build_identity, 4, "Manifest",
- "LoadableTrustCache", "Info", "Path");
- if (!p_tc_path) {
- qDebug() << "Error: Could not determine path for trust cache!";
- res = -1;
- goto leave;
- }
- plist_t p_dmg_path = plist_access_path(
- build_identity, 4, "Manifest", "PersonalizedDMG", "Info", "Path");
- if (!p_dmg_path) {
- qDebug() << "Error: Could not determine path for disk image!";
- res = -1;
- goto leave;
- }
- char *tc_path = string_build_path(
- image_path, plist_get_string_ptr(p_tc_path, NULL), NULL);
- unsigned char *trust_cache = NULL;
- uint64_t trust_cache_size = 0;
- if (!buffer_read_from_filename(tc_path, (char **)&trust_cache,
- &trust_cache_size)) {
- qDebug() << "Error: Trust cache does not exist at" << tc_path
- << "!";
- res = -1;
- goto leave;
- }
- mount_options = plist_new_dict();
- plist_dict_set_item(
- mount_options, "ImageTrustCache",
- plist_new_data((char *)trust_cache, trust_cache_size));
- free(trust_cache);
- char *dmg_path = string_build_path(
- image_path, plist_get_string_ptr(p_dmg_path, NULL), NULL);
- free(image_path);
- image_path = dmg_path;
- f = fopen(image_path, "rb");
- if (!f) {
- qDebug() << "Error opening image file" << image_path << ":"
- << strerror(errno);
- res = -1;
- goto leave;
- }
-
- unsigned char buf[8192];
- unsigned char sha384_digest[48];
- sha384_context ctx;
- sha384_init(&ctx);
- fstat(fileno(f), &fst);
- image_size = fst.st_size;
- while (!feof(f)) {
- ssize_t fr = fread(buf, 1, sizeof(buf), f);
- if (fr <= 0) {
- break;
- }
- sha384_update(&ctx, buf, fr);
- }
- rewind(f);
- sha384_final(&ctx, sha384_digest);
- unsigned char *manifest = NULL;
- unsigned int manifest_size = 0;
- /* check if the device already has a personalization manifest for this
- * image */
- if (mobile_image_mounter_query_personalization_manifest(
- mim, "DeveloperDiskImage", sha384_digest, sizeof(sha384_digest),
- &manifest, &manifest_size) == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- qDebug() << "Using existing personalization manifest from device.";
+ err = image_mounter_mount_developer(device->imageMounter, image_data,
+ image_len, signature_data,
+ signature_len);
+ if (err == NULL) {
+ printf("Developer image mounted successfully\n");
} else {
- /* we need to re-connect in this case */
- mobile_image_mounter_free(mim);
- mim = NULL;
- if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) !=
- MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- res = -1;
- goto leave;
- }
- qDebug() << "No personalization manifest, requesting from TSS...";
- unsigned char *nonce = NULL;
- unsigned int nonce_size = 0;
-
- /* create new TSS request and fill parameters */
- plist_t request = tss_request_new(NULL);
- plist_t params = plist_new_dict();
- tss_parameters_add_from_manifest(params, build_identity, 1);
-
- /* copy all `Ap,*` items from identifiers */
- plist_dict_iter di = NULL;
- plist_dict_new_iter(identifiers, &di);
- plist_t node = NULL;
- do {
- char *key = NULL;
- plist_dict_next_item(identifiers, di, &key, &node);
- if (node) {
- if (!strncmp(key, "Ap,", 3)) {
- plist_dict_set_item(request, key, plist_copy(node));
- }
- }
- free(key);
- } while (node);
- plist_mem_free(di);
-
- plist_dict_copy_uint(params, identifiers, "ApECID", "UniqueChipID");
- plist_dict_set_item(params, "ApProductionMode", plist_new_bool(1));
- plist_dict_set_item(params, "ApSecurityMode", plist_new_bool(1));
- plist_dict_set_item(params, "ApSupportsImg4", plist_new_bool(1));
-
- /* query nonce from image mounter service */
- merr = mobile_image_mounter_query_nonce(mim, "DeveloperDiskImage",
- &nonce, &nonce_size);
- if (merr == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- plist_dict_set_item(params, "ApNonce",
- plist_new_data((char *)nonce, nonce_size));
- } else {
- qDebug()
- << "ERROR: Failed to query nonce for developer disk image:"
- << merr;
- res = -1;
- goto leave;
- }
- mobile_image_mounter_free(mim);
- mim = NULL;
-
- plist_dict_set_item(
- params, "ApSepNonce",
- plist_new_data("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00",
- 20));
- plist_dict_set_item(params, "UID_MODE", plist_new_bool(0));
- tss_request_add_ap_tags(request, params, NULL);
- tss_request_add_common_tags(request, params, NULL);
- tss_request_add_ap_img4_tags(request, params);
- plist_free(params);
-
- /* request IM4M from TSS */
- plist_t response = tss_request_send(request, NULL);
- plist_free(request);
-
- plist_t p_manifest = plist_dict_get_item(response, "ApImg4Ticket");
- if (!PLIST_IS_DATA(p_manifest)) {
- qDebug() << "Failed to get Img4Ticket";
- res = -1;
- goto leave;
- }
-
- uint64_t m4m_len = 0;
- plist_get_data_val(p_manifest, (char **)&manifest, &m4m_len);
- manifest_size = m4m_len;
- plist_free(response);
- qDebug() << "Done.";
+ fprintf(stderr, "Failed to mount developer image: [%d] %s",
+ err->code, err->message);
+ goto cleanup;
}
- sig = manifest;
- sig_length = manifest_size;
-
- imagetype = "Personalized";
}
- if (asprintf(&targetname, "%s/%s", PKG_PATH, "staging.dimage") < 0) {
- qDebug() << "Out of memory!?";
- res = -1;
- goto leave;
- }
- if (asprintf(&mountname, "%s/%s", PATH_PREFIX, targetname) < 0) {
- qDebug() << "Out of memory!?";
- res = -1;
- goto leave;
- }
+cleanup:
- if (!imagetype) {
- imagetype = "Developer";
- }
-
- switch (disk_image_upload_type) {
- case DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE:
- qDebug() << "Uploading" << image_path;
- err = mobile_image_mounter_upload_image(mim, imagetype, image_size, sig,
- sig_length, mim_upload_cb, f);
- break;
- case DISK_IMAGE_UPLOAD_TYPE_AFC:
- default:
- qDebug() << "Uploading" << image_path << "--> afc:///" << targetname;
- plist_t fileinfo = NULL;
- if (afc_get_file_info_plist(afc, PKG_PATH, &fileinfo) !=
- AFC_E_SUCCESS) {
- if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) {
- qDebug() << "WARNING: Could not create directory" << PKG_PATH
- << "on device!";
- }
- }
- plist_free(fileinfo);
-
- uint64_t af = 0;
- if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) !=
- AFC_E_SUCCESS) ||
- !af) {
- qDebug() << "afc_file_open on" << targetname << "failed!";
- res = -1;
- goto leave;
- }
-
- char buf[8192];
- size_t amount = 0;
- do {
- amount = fread(buf, 1, sizeof(buf), f);
- if (amount > 0) {
- uint32_t written, total = 0;
- while (total < amount) {
- written = 0;
- if (afc_file_write(afc, af, buf + total, amount - total,
- &written) != AFC_E_SUCCESS) {
- qDebug() << "AFC Write error!";
- break;
- }
- total += written;
- }
- if (total != amount) {
- qDebug() << "Error: wrote only" << total << "of"
- << (unsigned int)amount;
- afc_file_close(afc, af);
- res = -1;
- goto leave;
- }
- }
- } while (amount > 0);
-
- afc_file_close(afc, af);
- break;
- }
-
- if (err != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- if (err == MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED) {
- qDebug() << "ERROR: Device is locked, can't mount. Unlock device "
- "and try again.";
- } else {
- qDebug() << "ERROR: Unknown error occurred, can't mount.";
- }
- res = -1;
- goto leave;
- }
-
- qDebug() << "Mounting...";
- err = mobile_image_mounter_mount_image_with_options(
- mim, mountname, sig, sig_length, imagetype, mount_options, &result);
- if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- if (result) {
- plist_t node = plist_dict_get_item(result, "Status");
- if (node) {
- char *status = NULL;
- plist_get_string_val(node, &status);
- if (status) {
- if (!strcmp(status, "Complete")) {
- qDebug() << "Done.";
- res = 0;
- } else {
- err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
- }
- free(status);
- } else {
- err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
- }
- } else {
- err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
- }
- if (res != 0) { // If not complete, log the error
- err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
- node = plist_dict_get_item(result, "Error");
- if (node) {
- char *error = NULL;
- plist_get_string_val(node, &error);
- if (error) {
- qDebug() << "Error:" << error;
- free(error);
- }
- node = plist_dict_get_item(result, "DetailedError");
- if (node) {
- const char *str = plist_get_string_ptr(node, NULL);
- auto sd_str = std::string(str);
- if (sd_str.find("already mounted at /Developer") !=
- std::string::npos) {
- // FIXME: need an error code for this
- qDebug() << "Image is already mounted";
- // res = 0;
- // err = MOBILE_IMAGE_MOUNTER_E_SUCCESS;
- } else {
- qDebug() << "DetailedError:" << str;
- }
- }
- }
- }
- }
- } else {
- qDebug() << "Error: mount_image returned" << err;
- }
-
-leave:
- if (f) {
- fclose(f);
- }
- if (result) {
- plist_free(result);
- }
- if (mim) {
- mobile_image_mounter_free(mim);
- }
- if (afc) {
- afc_client_free(afc);
- }
- if (lckd) {
- lockdownd_client_free(lckd);
- }
- if (image_path) {
- free(image_path);
- }
- if (image_sig_path) {
- free(image_sig_path);
- }
- if (sig) {
- free(sig);
- }
- if (mount_options) {
- plist_free(mount_options);
- }
- if (targetname) {
- free(targetname);
- }
- if (mountname) {
- free(mountname);
- }
+ if (image_data)
+ free(image_data);
+ if (signature_data)
+ free(signature_data);
return err;
}
\ No newline at end of file
diff --git a/src/core/services/query_mobilegestalt.cpp b/src/core/services/query_mobilegestalt.cpp
deleted file mode 100644
index 82e2a4e..0000000
--- a/src/core/services/query_mobilegestalt.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * iDescriptor: A free and open-source idevice management tool.
- *
- * Copyright (C) 2025 Uncore
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-#include "../../iDescriptor.h"
-#include "libimobiledevice/diagnostics_relay.h"
-#include
-#include
-
-bool query_mobile_gestalt(iDescriptorDevice *id_device, const QStringList &keys,
- uint32_t &xml_size, char *&xml_data)
-{
- if (!id_device) {
- qDebug() << "Invalid device";
- return false;
- }
-
- diagnostics_relay_client_t diagnostics_client = nullptr;
- if (diagnostics_relay_client_start_service(id_device->device,
- &diagnostics_client, nullptr) !=
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- qDebug() << "Failed to start diagnostics service";
- return false;
- }
-
- plist_t result = nullptr;
- plist_t keys_array = plist_new_array();
- for (const QString &key : keys) {
- plist_t key_node = plist_new_string(key.toStdString().c_str());
- plist_array_append_item(keys_array, key_node);
- }
-
- diagnostics_relay_error_t err = diagnostics_relay_query_mobilegestalt(
- diagnostics_client, keys_array, &result);
-
- plist_free(keys_array); // Free the keys array
-
- if (err != DIAGNOSTICS_RELAY_E_SUCCESS) {
- qDebug() << "Failed to query mobile gestalt";
- diagnostics_relay_client_free(diagnostics_client);
- return false;
- }
-
- if (!result) {
- qDebug() << "No result from mobile gestalt query";
- diagnostics_relay_client_free(diagnostics_client);
- return false;
- }
-
- plist_to_xml(result, &xml_data, &xml_size);
- plist_free(result); // Free the result plist
- diagnostics_relay_client_free(diagnostics_client);
-
- return true;
-}
diff --git a/src/core/services/restart.cpp b/src/core/services/restart.cpp
deleted file mode 100644
index a829009..0000000
--- a/src/core/services/restart.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * idevicediagnostics.c
- * Retrieves diagnostics information from device
- *
- * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "../../iDescriptor.h"
-#include
-#include
-#include
-
-bool restart(std::string _udid)
-{
- idevice_t device = NULL;
- lockdownd_client_t lockdown_client = NULL;
- diagnostics_relay_client_t diagnostics_client = NULL;
- lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
- lockdownd_service_descriptor_t service = NULL;
- const char *udid = _udid.c_str();
- int use_network = 0;
-
- if (idevice_new_with_options(&device, udid, IDEVICE_LOOKUP_USBMUX) !=
- IDEVICE_E_SUCCESS) {
- printf("ERROR: No device found, is it plugged in?\n");
- return false;
- }
-
- if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(
- device, &lockdown_client, TOOL_NAME))) {
- idevice_free(device);
- printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
- return false;
- }
-
- /* attempt to use newer diagnostics service available on iOS 5 and later */
- ret = lockdownd_start_service(
- lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
- if (ret == LOCKDOWN_E_INVALID_SERVICE) {
- /* attempt to use older diagnostics service */
- ret = lockdownd_start_service(
- lockdown_client, "com.apple.iosdiagnostics.relay", &service);
- }
- lockdownd_client_free(lockdown_client);
-
- if (ret != LOCKDOWN_E_SUCCESS) {
- idevice_free(device);
- printf("ERROR: Could not start diagnostics relay service: %s\n",
- lockdownd_strerror(ret));
- return false;
- }
-
- if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
- if (diagnostics_relay_client_new(device, service,
- &diagnostics_client) !=
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- printf("ERROR: Could not connect to diagnostics_relay!\n");
- } else {
-
- if (diagnostics_relay_restart(
- diagnostics_client,
- DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) ==
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- printf("Restarting device.\n");
- return true;
- } else {
- printf("ERROR: Failed to restart device.\n");
- }
- }
-
- diagnostics_relay_goodbye(diagnostics_client);
- diagnostics_relay_client_free(diagnostics_client);
- }
-
- return false;
-}
\ No newline at end of file
diff --git a/src/core/services/set_location.cpp b/src/core/services/set_location.cpp
index cfe8b0d..952ef8e 100644
--- a/src/core/services/set_location.cpp
+++ b/src/core/services/set_location.cpp
@@ -20,101 +20,80 @@
*/
#include "../../iDescriptor.h"
-#define DT_SIMULATELOCATION_SERVICE "com.apple.dt.simulatelocation"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#if defined(__APPLE__)
-#include
-#include
-#define htobe32(x) OSSwapHostToBigInt32(x)
-#elif defined(_WIN32)
-#include
-#define htobe32(x) htonl(x)
-#else
-#include
-#endif
-#include
enum { SET_LOCATION = 0, RESET_LOCATION = 1 };
-bool set_location(idevice_t device, char *lat, char *lon)
+bool set_location(void *device, char *lat, char *lon)
{
- uint32_t mode = 0;
- lockdownd_client_t lockdown = NULL;
- lockdownd_error_t lerr =
- lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
- try {
- /* code */
+ return false;
+ // uint32_t mode = 0;
+ // lockdownd_client_t lockdown = NULL;
+ // lockdownd_error_t lerr =
+ // lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
+ // try {
+ // /* code */
- if (lerr != LOCKDOWN_E_SUCCESS) {
- idevice_free(device);
- printf("ERROR: Could not connect to lockdownd: %s (%d)\n",
- lockdownd_strerror(lerr), lerr);
- return false;
- }
+ // if (lerr != LOCKDOWN_E_SUCCESS) {
+ // idevice_free(device);
+ // printf("ERROR: Could not connect to lockdownd: %s (%d)\n",
+ // lockdownd_strerror(lerr), lerr);
+ // return false;
+ // }
- lockdownd_service_descriptor_t svc = NULL;
- lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE,
- &svc);
- if (lerr != LOCKDOWN_E_SUCCESS) {
- unsigned int device_version = idevice_get_device_version(device);
- lockdownd_client_free(lockdown);
- idevice_free(device);
+ // lockdownd_service_descriptor_t svc = NULL;
+ // lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE,
+ // &svc);
+ // if (lerr != LOCKDOWN_E_SUCCESS) {
+ // unsigned int device_version = idevice_get_device_version(device);
+ // lockdownd_client_free(lockdown);
+ // idevice_free(device);
- return false;
- }
- lockdownd_client_free(lockdown);
+ // return false;
+ // }
+ // lockdownd_client_free(lockdown);
- service_client_t service = NULL;
+ // service_client_t service = NULL;
- service_error_t serr = service_client_new(device, svc, &service);
+ // service_error_t serr = service_client_new(device, svc, &service);
- lockdownd_service_descriptor_free(svc);
+ // lockdownd_service_descriptor_free(svc);
- if (serr != SERVICE_E_SUCCESS) {
- idevice_free(device);
- return false;
- }
+ // if (serr != SERVICE_E_SUCCESS) {
+ // idevice_free(device);
+ // return false;
+ // }
- uint32_t l;
- uint32_t s = 0;
+ // uint32_t l;
+ // uint32_t s = 0;
- l = htobe32(mode);
- service_send(service, (const char *)&l, 4, &s);
- if (mode == SET_LOCATION) {
- int len = 4 + strlen(lat) + 4 + strlen(lon);
- char *buf = (char *)malloc(len);
- uint32_t latlen;
- latlen = strlen(lat);
- l = htobe32(latlen);
- memcpy(buf, &l, 4);
- memcpy(buf + 4, lat, latlen);
- uint32_t longlen = strlen(lon);
- l = htobe32(longlen);
- memcpy(buf + 4 + latlen, &l, 4);
- memcpy(buf + 4 + latlen + 4, lon, longlen);
+ // l = htobe32(mode);
+ // service_send(service, (const char *)&l, 4, &s);
+ // if (mode == SET_LOCATION) {
+ // int len = 4 + strlen(lat) + 4 + strlen(lon);
+ // char *buf = (char *)malloc(len);
+ // uint32_t latlen;
+ // latlen = strlen(lat);
+ // l = htobe32(latlen);
+ // memcpy(buf, &l, 4);
+ // memcpy(buf + 4, lat, latlen);
+ // uint32_t longlen = strlen(lon);
+ // l = htobe32(longlen);
+ // memcpy(buf + 4 + latlen, &l, 4);
+ // memcpy(buf + 4 + latlen + 4, lon, longlen);
- s = 0;
- service_send(service, buf, len, &s);
- free(buf); // <-- free the buffer after use
- }
+ // s = 0;
+ // service_send(service, buf, len, &s);
+ // free(buf); // <-- free the buffer after use
+ // }
- return true;
- } catch (...) {
- if (lockdown) {
- lockdownd_client_free(lockdown);
- }
- if (device) {
- idevice_free(device);
- }
- qDebug() << "Exception occurred while setting location.";
- return false;
- }
+ // return true;
+ // } catch (...) {
+ // if (lockdown) {
+ // lockdownd_client_free(lockdown);
+ // }
+ // if (device) {
+ // idevice_free(device);
+ // }
+ // qDebug() << "Exception occurred while setting location.";
+ // return false;
+ // }
}
\ No newline at end of file
diff --git a/src/core/services/shutdown.cpp b/src/core/services/shutdown.cpp
deleted file mode 100644
index c0d3478..0000000
--- a/src/core/services/shutdown.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * idevicediagnostics.c
- * Retrieves diagnostics information from device
- *
- * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "../../iDescriptor.h"
-#include
-#include
-#include
-
-bool shutdown(idevice_t device)
-{
- lockdownd_client_t lockdown_client = NULL;
- diagnostics_relay_client_t diagnostics_client = NULL;
- lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
- lockdownd_service_descriptor_t service = NULL;
- const char *udid = NULL;
- int use_network = 0;
-
- if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(
- device, &lockdown_client, TOOL_NAME))) {
- idevice_free(device);
- printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
- return false;
- }
-
- /* attempt to use newer diagnostics service available on iOS 5 and later */
- ret = lockdownd_start_service(
- lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
- if (ret == LOCKDOWN_E_INVALID_SERVICE) {
- /* attempt to use older diagnostics service */
- ret = lockdownd_start_service(
- lockdown_client, "com.apple.iosdiagnostics.relay", &service);
- }
- lockdownd_client_free(lockdown_client);
-
- if (ret != LOCKDOWN_E_SUCCESS) {
- idevice_free(device);
- printf("ERROR: Could not start diagnostics relay service: %s\n",
- lockdownd_strerror(ret));
- return false;
- }
-
- if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
- if (diagnostics_relay_client_new(device, service,
- &diagnostics_client) !=
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- printf("ERROR: Could not connect to diagnostics_relay!\n");
- } else {
-
- if (diagnostics_relay_shutdown(
- diagnostics_client,
- DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) ==
- DIAGNOSTICS_RELAY_E_SUCCESS) {
- printf("Shutting down device.\n");
- return true;
- } else {
- printf("ERROR: Failed to shut down device.\n");
- }
- }
-
- diagnostics_relay_goodbye(diagnostics_client);
- diagnostics_relay_client_free(diagnostics_client);
- }
-
- if (service) {
- lockdownd_service_descriptor_free(service);
- service = NULL;
- }
-
- return false;
-}
\ No newline at end of file
diff --git a/src/core/services/take_screenshot.cpp b/src/core/services/take_screenshot.cpp
deleted file mode 100644
index 3e41254..0000000
--- a/src/core/services/take_screenshot.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * idevicescreenshot.c
- * Gets a screenshot from a device
- *
- * Copyright (C) 2010 Nikias Bassen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "../../iDescriptor.h"
-#include
-#include
-#include
-#include
-#include
-#include
-
-QImage get_image(const char *imgdata, uint64_t imgsize)
-{
- QByteArray byteArray(imgdata, static_cast(imgsize));
- QImage image;
- image.loadFromData(byteArray);
- return image;
-}
-
-TakeScreenshotResult take_screenshot(screenshotr_client_t shotr)
-{
- TakeScreenshotResult result;
- try {
- char *imgdata = NULL;
- uint64_t imgsize = 0;
- if (screenshotr_take_screenshot(shotr, &imgdata, &imgsize) ==
- SCREENSHOTR_E_SUCCESS) {
- QImage image = get_image(imgdata, imgsize);
- if (image.isNull()) {
- printf("Could not decode screenshot image!\n");
- } else {
- result.img = image;
- result.success = true;
- }
- // Always free imgdata after use!
- free(imgdata);
- }
- } catch (const std::exception &e) {
- qDebug() << "Exception occurred while taking screenshot:" << e.what();
- }
- // Always return result!
- return result;
-}
diff --git a/src/devdiskimagehelper.cpp b/src/devdiskimagehelper.cpp
index 56bb589..95cab5b 100644
--- a/src/devdiskimagehelper.cpp
+++ b/src/devdiskimagehelper.cpp
@@ -18,8 +18,10 @@
*/
#include "devdiskimagehelper.h"
+#include "appcontext.h"
#include "devdiskmanager.h"
#include "qprocessindicator.h"
+#include "servicemanager.h"
#include "settingsmanager.h"
#include
#include
@@ -29,8 +31,7 @@
DevDiskImageHelper::DevDiskImageHelper(iDescriptorDevice *device,
QWidget *parent)
- : QDialog(parent), m_device(device), m_isDownloading(false),
- m_isMounting(false)
+ : QDialog(parent), m_device(device)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle("Developer Disk Image - iDescriptor");
@@ -97,9 +98,8 @@ void DevDiskImageHelper::start()
m_loadingIndicator->start();
showStatus("Please wait...");
- unsigned int device_version = idevice_get_device_version(m_device->device);
- unsigned int deviceMajorVersion = (device_version >> 16) & 0xFF;
- unsigned int deviceMinorVersion = (device_version >> 8) & 0xFF;
+ unsigned int deviceMajorVersion =
+ m_device->deviceInfo.parsedDeviceVersion.major;
// FIXME:we dont have developer disk images for ios 6 and below
if (deviceMajorVersion > 5) {
@@ -114,7 +114,9 @@ void DevDiskImageHelper::start()
});
qDebug() << "isMountAvailable:" << isMountAvailable;
if (!isMountAvailable) {
- finishWithError("Failed to download compatible image.");
+ finishWithError(
+ "There is no compatible developer disk image available for " +
+ QString::number(deviceMajorVersion) + ".");
}
} else {
finishWithSuccess();
@@ -124,18 +126,15 @@ void DevDiskImageHelper::start()
void DevDiskImageHelper::checkAndMount()
{
- GetMountedImageResult result =
- DevDiskManager::sharedInstance()->getMountedImage(
- m_device->udid.c_str());
- qDebug() << "checkAndMount result:" << result.success
- << result.message.c_str() << QString::fromStdString(result.sig);
- if (!result.success) {
- showRetryUI(QString::fromStdString(result.message));
+ MountedImageInfo info = ServiceManager::getMountedImage(
+ AppContext::sharedInstance()->getDevice(m_device->udid));
+ if (info.err && info.err->code != NotFoundErrorCode) {
+ onMountButtonClicked();
return;
}
// If image is already mounted
- if (!result.sig.empty()) {
+ if (info.signature && info.signature_len) {
finishWithSuccess();
return;
}
@@ -148,12 +147,12 @@ void DevDiskImageHelper::onMountButtonClicked()
QString path = SettingsManager::sharedInstance()->mkDevDiskImgPath();
m_mountButton->setVisible(false);
m_loadingIndicator->start();
- m_isMounting = true;
// Check if we need to download first
- unsigned int device_version = idevice_get_device_version(m_device->device);
- unsigned int deviceMajorVersion = (device_version >> 16) & 0xFF;
- unsigned int deviceMinorVersion = (device_version >> 8) & 0xFF;
+ unsigned int deviceMajorVersion =
+ m_device->deviceInfo.parsedDeviceVersion.major;
+ unsigned int deviceMinorVersion =
+ m_device->deviceInfo.parsedDeviceVersion.minor;
QList images = DevDiskManager::sharedInstance()->parseImageList(
path, deviceMajorVersion, deviceMinorVersion, "", 0);
@@ -174,32 +173,14 @@ void DevDiskImageHelper::onMountButtonClicked()
}
if (hasDownloadedImage) {
- // Mount directly
+ // // Mount directly
+ m_downloadingVersion = versionToMount;
showStatus("Mounting developer disk image...");
-
- mobile_image_mounter_error_t err =
- DevDiskManager::sharedInstance()->mountImage(versionToMount,
- m_device);
-
- m_isMounting = false;
- if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- showStatus("Developer disk image mounted successfully");
- finishWithSuccess();
- } else if (err == MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED) {
- showRetryUI(
- "Device is locked. Please unlock your device and try again.");
- } else {
- showRetryUI("Failed to mount developer disk image.\n"
- "Please ensure:\n"
- "• Device is unlocked\n"
- "• Using a genuine cable\n"
- "• Developer mode is enabled (iOS 16+)");
- }
+ onImageDownloadFinished(versionToMount, true, "");
} else {
// Need to download first
showStatus(
"Downloading developer disk image...\nThis may take a moment.");
- m_isDownloading = true;
// Connect to download signals
connect(DevDiskManager::sharedInstance(),
@@ -222,35 +203,43 @@ void DevDiskImageHelper::onImageDownloadFinished(const QString &version,
bool success,
const QString &errorMessage)
{
- if (!m_isDownloading || version != m_downloadingVersion) {
+ if (version != m_downloadingVersion) {
+ qDebug() << "Ignoring download finished for version" << version
+ << "expected" << m_downloadingVersion;
return;
}
- m_isDownloading = false;
-
if (!success) {
showRetryUI("Failed to download developer disk image:\n" +
errorMessage);
return;
}
- // Download successful, now mount
showStatus("Download complete. Mounting...");
- mobile_image_mounter_error_t err =
- DevDiskManager::sharedInstance()->mountImage(version, m_device);
+ auto paths = DevDiskManager::sharedInstance()->getPathsForVersion(version);
- if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
- showStatus("Developer disk image mounted successfully");
- finishWithSuccess();
- } else if (err == MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED) {
+ IdeviceFfiError *err =
+ ServiceManager::mountImage(m_device, paths.first.toStdString().c_str(),
+ paths.second.toStdString().c_str());
+
+ if (err == nullptr) {
+ return finishWithSuccess();
+ }
+
+ qDebug() << "onImageDownloadFinished:" << err->code
+ << QString::fromStdString(err->message);
+
+ if (err->code == DeviceLockedMountErrorCode) {
showRetryUI(
"Device is locked. Please unlock your device and try again.");
+
} else {
showRetryUI(
"Failed to mount developer disk image.\n"
"Please ensure the device is unlocked and using a genuine cable.");
}
+ idevice_error_free(err);
}
void DevDiskImageHelper::showRetryUI(const QString &errorMessage)
diff --git a/src/devdiskimagehelper.h b/src/devdiskimagehelper.h
index 9bfbedf..a589448 100644
--- a/src/devdiskimagehelper.h
+++ b/src/devdiskimagehelper.h
@@ -66,8 +66,6 @@ private:
QPushButton *m_retryButton;
QPushButton *m_cancelButton;
- bool m_isDownloading;
- bool m_isMounting;
QString m_downloadingVersion;
};
diff --git a/src/devdiskimageswidget.cpp b/src/devdiskimageswidget.cpp
index 3606463..93a72bb 100644
--- a/src/devdiskimageswidget.cpp
+++ b/src/devdiskimageswidget.cpp
@@ -22,6 +22,7 @@
#include "devdiskmanager.h"
#include "iDescriptor.h"
#include "qprocessindicator.h"
+#include "servicemanager.h"
#include "settingsmanager.h"
#include
#include
@@ -46,12 +47,13 @@
#include
#include
#include
-#include
#include
DevDiskImagesWidget::DevDiskImagesWidget(iDescriptorDevice *device,
QWidget *parent)
- : QWidget{parent}, m_currentDevice(device)
+ : QWidget{parent},
+ m_currentDeviceUdid(
+ device != nullptr ? QString::fromStdString(device->udid) : QString())
{
setupUi();
connect(DevDiskManager::sharedInstance(), &DevDiskManager::imageListFetched,
@@ -171,34 +173,34 @@ void DevDiskImagesWidget::onDeviceSelectionChanged(int index)
if (device == nullptr)
return;
- m_currentDevice = device;
+ m_currentDeviceUdid = QString::fromStdString(device->udid);
displayImages();
}
void DevDiskImagesWidget::displayImages()
{
+ qDebug() << "Displaying images for device";
m_imageListWidget->clear();
- int deviceMajorVersion = 0;
- int deviceMinorVersion = 0;
- bool hasConnectedDevice = false;
-
- if (m_currentDevice && m_currentDevice->device) {
- unsigned int device_version =
- idevice_get_device_version(m_currentDevice->device);
- deviceMajorVersion = (device_version >> 16) & 0xFF;
- deviceMinorVersion = (device_version >> 8) & 0xFF;
- hasConnectedDevice = true;
+ // Look up device by UDID
+ iDescriptorDevice *currentDevice = nullptr;
+ if (!m_currentDeviceUdid.isEmpty()) {
+ currentDevice = AppContext::sharedInstance()->getDevice(
+ m_currentDeviceUdid.toStdString());
}
+ bool hasConnectedDevice = (currentDevice != nullptr);
+
+ int major = hasConnectedDevice
+ ? currentDevice->deviceInfo.parsedDeviceVersion.major
+ : 0;
+ int minor = hasConnectedDevice
+ ? currentDevice->deviceInfo.parsedDeviceVersion.minor
+ : 0;
- qDebug() << "Device version:" << deviceMajorVersion << "."
- << deviceMinorVersion << "displayImages";
- // Parse images using manager
QString path = SettingsManager::sharedInstance()->mkDevDiskImgPath();
QList allImages =
DevDiskManager::sharedInstance()->parseImageList(
- path, deviceMajorVersion, deviceMinorVersion, m_mounted_sig.c_str(),
- m_mounted_sig_len);
+ path, major, minor, m_mounted_sig.c_str(), m_mounted_sig_len);
qDebug() << "Total images:" << allImages.size();
@@ -307,8 +309,7 @@ void DevDiskImagesWidget::displayImages()
// Show device info if available
if (hasConnectedDevice) {
- QString deviceVersion =
- QString("%1.%2").arg(deviceMajorVersion).arg(deviceMinorVersion);
+ QString deviceVersion = QString("%1.%2").arg(major).arg(minor);
m_statusLabel->setText(
QString("Connected device: iOS %1 - Compatible images shown at top")
.arg(deviceVersion));
@@ -499,7 +500,7 @@ void DevDiskImagesWidget::updateDeviceList()
auto devices = AppContext::sharedInstance()->getAllDevices();
if (devices.isEmpty()) {
- m_currentDevice = nullptr;
+ m_currentDeviceUdid.clear();
m_check_mountedButton->setEnabled(false);
m_deviceComboBox->setEnabled(false);
} else {
@@ -511,6 +512,8 @@ void DevDiskImagesWidget::updateDeviceList()
if (m_deviceComboBox->count() > 0 &&
m_deviceComboBox->currentIndex() >= 0) {
currentUdid = m_deviceComboBox->currentData().toString();
+ } else if (!m_currentDeviceUdid.isEmpty()) {
+ currentUdid = m_currentDeviceUdid;
}
m_deviceComboBox->clear();
@@ -582,61 +585,81 @@ void DevDiskImagesWidget::mountImage(const QString &version)
m_mountButton->setEnabled(false);
m_mountButton->setText("Mounting...");
- mobile_image_mounter_error_t err =
- DevDiskManager::sharedInstance()->mountImage(version, m_currentDevice);
-
auto updateUI = [&]() {
m_mountButton->setEnabled(true);
m_mountButton->setText("Mount");
m_deviceComboBox->setEnabled(true);
};
- switch (err) {
- case MOBILE_IMAGE_MOUNTER_E_INVALID_ARG:
- QMessageBox::critical(this, "Mount Failed",
- "Invalid argument provided for mounting.");
- updateUI();
- return;
- case MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED:
- QMessageBox::critical(this, "Mount Failed",
- "The device is locked. Please unlock it and try "
- "again.");
- updateUI();
- return;
- case MOBILE_IMAGE_MOUNTER_E_SUCCESS:
+ auto paths = DevDiskManager::sharedInstance()->getPathsForVersion(version);
+
+ MountedImageInfo info = ServiceManager::getMountedImage(
+ AppContext::sharedInstance()->getDevice(udid.toStdString()));
+
+ if (info.err == nullptr && info.signature && info.signature_len) {
+ qDebug() << "Mount image: already mounted sig found"
+ << QString::fromStdString(std::string((char *)info.signature,
+ info.signature_len));
+ QMessageBox::information(this, "Already Mounted",
+ QString("A developer disk image is already "
+ "mounted on %1.")
+ .arg(m_deviceComboBox->currentText()));
+ return updateUI();
+ } else if (info.err->code == DeviceLockedMountErrorCode) {
+ /* Never returns DeviceLockedMountErrorCode when doing
+ image_mounter_lookup_image but maybe used in future */
+ } else if (info.err->code == NotFoundErrorCode) {
+ // OK, no image mounted
+ qDebug() << "Mount image: no mounted image found";
+ } else {
+ QMessageBox::critical(
+ this, "Mount Check Failed",
+ QString("Failed to check mounted image on %1. Try with a "
+ "genuine cable.")
+ .arg(m_deviceComboBox->currentText()));
+ mounted_image_info_free(info);
+ return updateUI();
+ }
+
+ mounted_image_info_free(info);
+
+ iDescriptorDevice *currentDevice =
+ m_currentDeviceUdid.isEmpty() ? nullptr
+ : AppContext::sharedInstance()->getDevice(
+ m_currentDeviceUdid.toStdString());
+
+ if (!currentDevice) {
+ QMessageBox::warning(this, "No Device",
+ "Device is no longer connected.");
+ return updateUI();
+ }
+
+ IdeviceFfiError *err = ServiceManager::mountImage(
+ currentDevice, paths.first.toStdString().c_str(),
+ paths.second.toStdString().c_str());
+
+ if (err == nullptr) {
QMessageBox::information(this, "Success",
QString("Image mounted successfully on %1.")
.arg(m_deviceComboBox->currentText()));
- displayImages(); // Refresh to show mounted status
- updateUI();
- break;
- default:
- GetMountedImageResult result =
- DevDiskManager::sharedInstance()->getMountedImage(
- udid.toStdString().c_str());
- /*
- * FIXME: there is no error enum like
- * MOBILE_IMAGE_MOUNTER_E_ALREADY_MOUNTED so we work around here
- */
- qDebug() << "Mount result:" << result.success << result.message.c_str()
- << QString::fromStdString(result.sig);
- if (result.success && !result.sig.empty()) {
- m_mounted_sig = result.sig;
- m_mounted_sig_len = result.sig.size();
- updateUI();
- displayImages();
- QMessageBox::information(this, "Already Mounted",
- "There is already a developer disk image "
- "mounted on the device.");
- return;
- }
+ return updateUI();
+ }
+ qDebug() << "Mount image result:" << err->code
+ << QString::fromStdString(err->message);
+
+ if (err->code == DeviceLockedMountErrorCode) {
+ QMessageBox::critical(this, "Mount Failed",
+ "The device is locked. Please unlock it and try"
+ " again.");
+ } else {
QMessageBox::critical(
this, "Mount Failed",
QString("Failed to mount image on %1. Try with a genuine cable.")
.arg(m_deviceComboBox->currentText()));
- updateUI();
}
+ idevice_error_free(err);
+ updateUI();
}
void DevDiskImagesWidget::closeEvent(QCloseEvent *event)
@@ -668,41 +691,65 @@ void DevDiskImagesWidget::closeEvent(QCloseEvent *event)
event->accept();
}
-// Toolbox clicked: "Developer Disk Images"
-// terminate called after throwing an instance of 'std::logic_error'
-// what(): basic_string: construction from null is not valid
-
void DevDiskImagesWidget::checkMountedImage()
{
- // just in case
- if (!m_currentDevice || !m_currentDevice->device) {
+ iDescriptorDevice *currentDevice =
+ m_currentDeviceUdid.isEmpty() ? nullptr
+ : AppContext::sharedInstance()->getDevice(
+ m_currentDeviceUdid.toStdString());
+
+ if (!currentDevice) {
+ qDebug() << "No device selected";
+ auto devices = AppContext::sharedInstance()->getAllDevices();
+ for (const auto &dev : devices) {
+ qDebug() << "Device:"
+ << QString::fromStdString(dev->deviceInfo.deviceName)
+ << "UDID:" << QString::fromStdString(dev->udid);
+ }
return;
}
if (m_deviceComboBox->currentIndex() < 0) {
+ qDebug() << "No device selected in combo box";
return;
}
- GetMountedImageResult result =
- DevDiskManager::sharedInstance()->getMountedImage(
- m_currentDevice->udid.c_str());
+ /*
+ older devices return something like this:
+ {
+ "ImagePresent": true,
+ "ImageSignature": <7b16200b 2ead1830 a59809d1 51e9060b ... 8a 9844eb07
+ e0b8e0>, "Status": "Complete"
+ }
+ */
+ MountedImageInfo info = ServiceManager::getMountedImage(currentDevice);
- qDebug() << "checkMountedImage result:" << result.success
- << result.message.c_str() << QString::fromStdString(result.sig);
-
- if (result.success && !result.sig.empty()) {
- m_mounted_sig = result.sig;
- m_mounted_sig_len = result.sig.size();
+ if (info.err == nullptr && info.signature != nullptr &&
+ info.signature_len > 0) {
+ m_mounted_sig = std::string(
+ reinterpret_cast(info.signature), info.signature_len);
+ m_mounted_sig_len = info.signature_len;
displayImages(); // Refresh to show mounted status
QMessageBox::information(
this, "Check Mounted Image",
"There is already a developer disk image mounted on the device.");
- return;
+ mounted_image_info_free(info);
+ } else if (info.err->code == DeviceLockedMountErrorCode) {
+ QMessageBox::critical(this, "Device Locked",
+ "The device is locked. Please unlock it and try"
+ " again.");
+ mounted_image_info_free(info);
+ } else if (info.err->code == NotFoundErrorCode) {
+ QMessageBox::critical(
+ this, "No Mounted Image",
+ "No developer disk image is mounted on the device.");
+ mounted_image_info_free(info);
+ } else {
+ QMessageBox::critical(
+ this, "Check Mounted Image Failed",
+ QString("Failed to check mounted image on %1. Try with a "
+ "genuine cable. Error message: %2")
+ .arg(m_deviceComboBox->currentText())
+ .arg(QString::fromStdString(info.err->message)));
+ mounted_image_info_free(info);
}
-
- QString errorMsg = QString::fromStdString(result.message);
- if (errorMsg.isEmpty()) {
- errorMsg = "Unknown error occurred while checking mounted image";
- }
-
- QMessageBox::warning(this, "Check Mounted Image Failed", errorMsg);
}
diff --git a/src/devdiskimageswidget.h b/src/devdiskimageswidget.h
index d1feb60..c6db239 100644
--- a/src/devdiskimageswidget.h
+++ b/src/devdiskimageswidget.h
@@ -86,7 +86,7 @@ private:
QPushButton *m_check_mountedButton;
QProcessIndicator *m_processIndicator;
- iDescriptorDevice *m_currentDevice;
+ QString m_currentDeviceUdid;
QStringList m_compatibleVersions;
QStringList m_otherVersions;
diff --git a/src/devdiskmanager.cpp b/src/devdiskmanager.cpp
index d2d110d..3bdf20a 100644
--- a/src/devdiskmanager.cpp
+++ b/src/devdiskmanager.cpp
@@ -19,6 +19,7 @@
#include "devdiskmanager.h"
#include "iDescriptor.h"
+#include "servicemanager.h"
#include "settingsmanager.h"
#include
#include
@@ -31,7 +32,6 @@
#include
#include
#include
-#include
DevDiskManager *DevDiskManager::sharedInstance()
{
@@ -326,9 +326,10 @@ bool DevDiskManager::downloadCompatibleImage(iDescriptorDevice *device,
std::function callback)
{
QString path = SettingsManager::sharedInstance()->mkDevDiskImgPath();
- unsigned int device_version = idevice_get_device_version(device->device);
- unsigned int deviceMajorVersion = (device_version >> 16) & 0xFF;
- unsigned int deviceMinorVersion = (device_version >> 8) & 0xFF;
+ unsigned int deviceMajorVersion =
+ device->deviceInfo.parsedDeviceVersion.major;
+ unsigned int deviceMinorVersion =
+ device->deviceInfo.parsedDeviceVersion.minor;
qDebug() << "Device version:" << deviceMajorVersion << "."
<< deviceMinorVersion;
QList images =
@@ -405,37 +406,36 @@ bool DevDiskManager::downloadCompatibleImage(iDescriptorDevice *device,
bool DevDiskManager::mountCompatibleImage(iDescriptorDevice *device)
{
QString path = SettingsManager::sharedInstance()->mkDevDiskImgPath();
- unsigned int device_version = idevice_get_device_version(device->device);
- unsigned int deviceMajorVersion = (device_version >> 16) & 0xFF;
- unsigned int deviceMinorVersion = (device_version >> 8) & 0xFF;
QList images =
- parseImageList(path, deviceMajorVersion, deviceMinorVersion, "", 0);
+ parseImageList(path, device->deviceInfo.parsedDeviceVersion.major,
+ device->deviceInfo.parsedDeviceVersion.minor, "", 0);
+ return false;
// 1. Try to mount an already downloaded compatible image
- for (const ImageInfo &info : images) {
- if (info.compatibility != ImageCompatibility::Compatible &&
- info.compatibility != ImageCompatibility::MaybeCompatible) {
- continue;
- }
- if (info.isDownloaded) {
- qDebug() << "There is a compatible image already downloaded:"
- << info.version;
- qDebug() << "Attempting to mount image version" << info.version
- << "on device:" << device->udid.c_str();
- if (MOBILE_IMAGE_MOUNTER_E_SUCCESS ==
- mountImage(info.version, device)) {
- qDebug() << "Mounted existing image version" << info.version
- << "on device:" << device->udid.c_str();
- return true;
- } else {
- qDebug() << "Failed to mount existing image version"
- << info.version
- << "on device:" << device->udid.c_str();
- return false;
- }
- }
- }
+ // for (const ImageInfo &info : images) {
+ // if (info.compatibility != ImageCompatibility::Compatible &&
+ // info.compatibility != ImageCompatibility::MaybeCompatible) {
+ // continue;
+ // }
+ // if (info.isDownloaded) {
+ // qDebug() << "There is a compatible image already downloaded:"
+ // << info.version;
+ // qDebug() << "Attempting to mount image version" << info.version
+ // << "on device:" << device->udid.c_str();
+ // if (MOBILE_IMAGE_MOUNTER_E_SUCCESS ==
+ // mountImage(info.version, device)) {
+ // qDebug() << "Mounted existing image version" << info.version
+ // << "on device:" << device->udid.c_str();
+ // return true;
+ // } else {
+ // qDebug() << "Failed to mount existing image version"
+ // << info.version
+ // << "on device:" << device->udid.c_str();
+ // return false;
+ // }
+ // }
+ // }
// 2. If none are downloaded, download the newest compatible one
for (const ImageInfo &info : images) {
@@ -492,19 +492,38 @@ bool DevDiskManager::mountCompatibleImage(iDescriptorDevice *device)
return false;
}
-mobile_image_mounter_error_t
-DevDiskManager::mountImage(const QString &version, iDescriptorDevice *device)
+bool DevDiskManager::mountImage(const QString &version,
+ iDescriptorDevice *device)
{
const QString downloadPath =
SettingsManager::sharedInstance()->devdiskimgpath();
if (!isImageDownloaded(version, downloadPath)) {
- return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
+ return false;
}
QString versionPath = QDir(downloadPath).filePath(version);
- return mount_dev_image(device->device,
- device->deviceInfo.parsedDeviceVersion,
- versionPath.toUtf8().constData());
+ return mount_dev_image(device,
+ QDir(versionPath)
+ .filePath("DeveloperDiskImage.dmg")
+ .toUtf8()
+ .constData(),
+ QDir(versionPath)
+ .filePath("DeveloperDiskImage.dmg.signature")
+ .toUtf8()
+ .constData());
+}
+
+std::pair
+DevDiskManager::getPathsForVersion(const QString &version)
+{
+ const QString downloadPath =
+ SettingsManager::sharedInstance()->devdiskimgpath();
+ QString versionPath = QDir(downloadPath).filePath(version);
+ QString dmgPath = QDir(versionPath).filePath("DeveloperDiskImage.dmg");
+ QString sigPath =
+ QDir(versionPath).filePath("DeveloperDiskImage.dmg.signature");
+
+ return {dmgPath, sigPath};
}
void DevDiskManager::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
@@ -624,79 +643,4 @@ bool DevDiskManager::compareSignatures(const char *signature_file_path,
free(local_sig);
return matches;
-}
-
-/*
- older devices return something like this:
- {
- "ImagePresent": true,
- "ImageSignature": <7b16200b 2ead1830 a59809d1 51e9060b ... 8a 9844eb07
- e0b8e0>, "Status": "Complete"
- }
-*/
-GetMountedImageResult DevDiskManager::getMountedImage(const char *udid)
-{
- /*
- FIXME: _get_mounted_image can return MOBILE_IMAGE_MOUNTER_E_SUCCESS even
- if the device is locked so we are going to go off of the result
- dictionary
- */
- plist_t result = _get_mounted_image(udid);
- plist_print(result);
- const char *lockedErr = "DeviceLocked";
-
- PlistNavigator r = PlistNavigator(result);
-
- std::string error = r["Error"].getString();
-
- if (!error.empty()) {
- plist_free(result);
- if (error == lockedErr) {
- return GetMountedImageResult{
- false, "", "Device is locked, please unlock it and try again."};
- } else
- return GetMountedImageResult{false, "", "Unknown error"};
- }
-
- // for older devices
- bool image_present = r["ImagePresent"].getBool();
-
- /* FIXME: returning a madeup sig because iDescriptorTool::MountDevImage
- * depends on it in toolboxwidget.cpp we can read the actual signature from
- * the device but it’s not really necessary since we
- * just need to know if there is an image mounted or
- * not also we would need to check the ios version
- * to know whether to treat ImageSignature as plist array or data
- */
- if (image_present) {
- plist_free(result);
- return GetMountedImageResult{true, "FIXME",
- "There is already an image mounted."};
- }
-
- plist_t sig_array_node = r["ImageSignature"].getNode();
-
- if (sig_array_node == NULL) {
- plist_free(result);
- return GetMountedImageResult{true, "", "No disk image mounted"};
- }
-
- char *mounted_sig = nullptr;
- uint64_t mounted_sig_len = 0;
- // get the signature
- if (sig_array_node && plist_get_node_type(sig_array_node) == PLIST_ARRAY &&
- plist_array_get_size(sig_array_node) > 0) {
- plist_t sig_data_node = plist_array_get_item(sig_array_node, 0);
- if (sig_data_node && plist_get_node_type(sig_data_node) == PLIST_DATA) {
- plist_get_data_val(sig_data_node, &mounted_sig, &mounted_sig_len);
- }
- }
- std::string mounted_sig_str(mounted_sig ? mounted_sig : "");
- free(mounted_sig);
- plist_free(result);
- if (mounted_sig_str.empty()) {
- return GetMountedImageResult{
- true, "", "No disk image mounted (No signature found)"};
- }
- return GetMountedImageResult{true, mounted_sig_str, "Success"};
}
\ No newline at end of file
diff --git a/src/devdiskmanager.h b/src/devdiskmanager.h
index ba995d3..6d49071 100644
--- a/src/devdiskmanager.h
+++ b/src/devdiskmanager.h
@@ -27,7 +27,6 @@
#include
#include
#include
-#include
class DevDiskManager : public QObject
{
@@ -50,16 +49,15 @@ public:
// Mount operations
- mobile_image_mounter_error_t mountImage(const QString &version,
- iDescriptorDevice *device);
+ bool mountImage(const QString &version, iDescriptorDevice *device);
bool unmountImage();
+ std::pair getPathsForVersion(const QString &version);
// Signature comparison
bool compareSignatures(const char *signature_file_path,
const char *mounted_sig, uint64_t mounted_sig_len);
QByteArray getImageListData() const { return m_imageListJsonData; }
- GetMountedImageResult getMountedImage(const char *udid);
bool mountCompatibleImage(iDescriptorDevice *device);
bool downloadCompatibleImage(iDescriptorDevice *device,
std::function callback);
diff --git a/src/devicedatabase.cpp b/src/devicedatabase.cpp
index 77dff79..5b5767f 100644
--- a/src/devicedatabase.cpp
+++ b/src/devicedatabase.cpp
@@ -570,5 +570,5 @@ std::string DeviceDatabase::parseRegionInfo(const std::string &code)
if (code == "C/A")
return "Canada (English, French)";
- return "Unknown Region (" + code + ")";
+ return code;
}
\ No newline at end of file
diff --git a/src/deviceimagewidget.cpp b/src/deviceimagewidget.cpp
index 6723686..fab01cb 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,26 +161,12 @@ QString DeviceImageWidget::getMockupNameFromDisplayName(
int DeviceImageWidget::getIosVersionFromDevice() const
{
- unsigned int version = idevice_get_device_version(m_device->device);
+ unsigned int version = m_device->deviceInfo.parsedDeviceVersion.major;
if (version > 0) {
- int majorVersion = (version >> 16) & 0xFF;
- return majorVersion;
+ return version;
}
- // Fallback: parse from productVersion string
- QString versionString =
- QString::fromStdString(m_device->deviceInfo.productVersion);
- QStringList parts = versionString.split('.');
- if (!parts.isEmpty()) {
- bool ok;
- int majorVersion = parts.first().toInt(&ok);
- if (ok) {
- return majorVersion;
- }
- }
-
- // If all else fails, return unknown version (will use ios26 wallpaper)
return 0;
}
diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp
index 2ef7417..b02f1d0 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
@@ -76,21 +76,22 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
ZIconWidget *shutdownBtn = new ZIconWidget(
QIcon(":/resources/icons/IcOutlinePowerSettingsNew.png"), "Shutdown",
- 1.0, this);
- connect(shutdownBtn, &ZIconWidget::clicked, this,
- [device]() { ToolboxWidget::shutdownDevice(device); });
+ this);
+ shutdownBtn->setIconSize(QSize(20, 20));
+ // connect(shutdownBtn, &ZIconWidget::clicked, this,
+ // [device]() { ToolboxWidget::shutdownDevice(device); });
- ZIconWidget *restartBtn =
- new ZIconWidget(QIcon(":/resources/icons/IcTwotoneRestartAlt.png"),
- "Restart", 1.0, this);
- connect(restartBtn, &ZIconWidget::clicked, this,
- [device]() { ToolboxWidget::restartDevice(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); });
- ZIconWidget *recoveryBtn =
- new ZIconWidget(QIcon(":/resources/icons/HugeiconsWrench01.png"),
- "Recovery", 1.0, this);
- connect(recoveryBtn, &ZIconWidget::clicked, this,
- [device]() { ToolboxWidget::_enterRecoveryMode(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); });
actionsLayout->addWidget(shutdownBtn);
actionsLayout->addWidget(restartBtn);
@@ -261,25 +262,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:",
@@ -324,7 +327,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 =
@@ -343,16 +346,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() {}
@@ -372,47 +375,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 eba3500..8ae5cfa 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) {
@@ -142,98 +145,102 @@ void DeviceManagerWidget::addDevice(iDescriptorDevice *device)
QString tabTitle = QString::fromStdString(device->deviceInfo.productType);
m_stackedWidget->addWidget(deviceWidget);
- m_deviceWidgets[device->udid] =
- std::pair{deviceWidget, m_sidebar->addDevice(tabTitle, device->udid)};
+ m_deviceWidgets[device->udid] = std::pair{
+ deviceWidget, m_sidebar->addDevice(tabTitle, device->udid,
+ device->deviceInfo.isWireless)};
}
-#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)
@@ -330,18 +337,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