WIP: implement avahi service

This commit is contained in:
uncor3
2025-10-03 20:43:44 +00:00
parent d6282762b1
commit 15a70c62ca
5 changed files with 669 additions and 47 deletions
+9
View File
@@ -32,6 +32,12 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg SvgWidgets Mu
# Add QTermWidget
pkg_check_modules(QTERMWIDGET REQUIRED IMPORTED_TARGET qtermwidget6)
# Add Avahi for network device discovery
pkg_check_modules(AVAHI_CLIENT REQUIRED IMPORTED_TARGET avahi-client)
# pkg_check_modules(AVAHI_CLIENT REQUIRED IMPORTED_TARGET avahi-client)
# pkg_check_modules(AVAHI_COMMON REQUIRED IMPORTED_TARGET avahi-common)
# Link directly to libraries in /usr/local/lib instead of using pkg-config
# Force NO_DEFAULT_PATH to only search in /usr/local/lib
find_library(IMOBILEDEVICE_LIBRARY
@@ -174,6 +180,7 @@ find_package(Qt6 REQUIRED COMPONENTS QuickWidgets)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
find_package(Qt6 REQUIRED COMPONENTS MultimediaWidgets)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_add_executable(iDescriptor
@@ -211,6 +218,7 @@ target_link_libraries(iDescriptor PRIVATE
PkgConfig::PLIST
PkgConfig::QRENCODE
PkgConfig::QTERMWIDGET
PkgConfig::AVAHI_CLIENT
airplay
ipatool-go
)
@@ -221,6 +229,7 @@ if(APPLE)
${SECURITY_FRAMEWORK}
${COREFOUNDATION_FRAMEWORK}
)
target_link_libraries(iDescriptor PRIVATE Qt6::Widgets)
endif()
# Add compile definition for source directory
+225
View File
@@ -0,0 +1,225 @@
#include "avahi_service.h"
#include <QDebug>
#include <QMutexLocker>
#include <avahi-common/error.h>
#include <avahi-common/malloc.h>
AvahiService::AvahiService(QObject *parent)
: QObject(parent), m_simplePoll(nullptr), m_client(nullptr),
m_serviceBrowser(nullptr), m_pollTimer(new QTimer(this)), m_running(false)
{
connect(m_pollTimer, &QTimer::timeout, this, &AvahiService::pollAvahi);
}
AvahiService::~AvahiService() { stopBrowsing(); }
void AvahiService::startBrowsing()
{
if (m_running)
return;
qDebug() << "Starting Avahi browsing for Apple devices";
initializeAvahi();
if (m_simplePoll) {
m_pollTimer->start(100); // Poll every 100ms
m_running = true;
}
}
void AvahiService::stopBrowsing()
{
if (!m_running)
return;
qDebug() << "Stopping Avahi browsing";
m_running = false;
m_pollTimer->stop();
cleanupAvahi();
QMutexLocker locker(&m_devicesMutex);
m_networkDevices.clear();
}
QList<NetworkDevice> AvahiService::getNetworkDevices() const
{
QMutexLocker locker(&m_devicesMutex);
return m_networkDevices;
}
void AvahiService::pollAvahi()
{
if (m_simplePoll && m_running) {
avahi_simple_poll_iterate(m_simplePoll, 0); // Non-blocking
}
}
void AvahiService::initializeAvahi()
{
int error;
m_simplePoll = avahi_simple_poll_new();
if (!m_simplePoll) {
qWarning() << "Failed to create Avahi simple poll";
return;
}
m_client =
avahi_client_new(avahi_simple_poll_get(m_simplePoll),
(AvahiClientFlags)0, clientCallback, this, &error);
if (!m_client) {
qWarning() << "Failed to create Avahi client:" << avahi_strerror(error);
cleanupAvahi();
return;
}
}
void AvahiService::cleanupAvahi()
{
if (m_serviceBrowser) {
avahi_service_browser_free(m_serviceBrowser);
m_serviceBrowser = nullptr;
}
if (m_client) {
avahi_client_free(m_client);
m_client = nullptr;
}
if (m_simplePoll) {
avahi_simple_poll_free(m_simplePoll);
m_simplePoll = nullptr;
}
}
void AvahiService::clientCallback(AvahiClient *client, AvahiClientState state,
void *userdata)
{
AvahiService *service = static_cast<AvahiService *>(userdata);
if (state == AVAHI_CLIENT_S_RUNNING) {
qDebug() << "Avahi client running, creating service browser";
service->m_serviceBrowser = avahi_service_browser_new(
client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_apple-mobdev2._tcp",
nullptr, (AvahiLookupFlags)0, browseCallback, userdata);
if (!service->m_serviceBrowser) {
qWarning() << "Failed to create service browser:"
<< avahi_strerror(avahi_client_errno(client));
}
} else if (state == AVAHI_CLIENT_FAILURE) {
qWarning() << "Avahi client failure:"
<< avahi_strerror(avahi_client_errno(client));
service->m_running = false;
}
}
void AvahiService::browseCallback(AvahiServiceBrowser *browser,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event, const char *name,
const char *type, const char *domain,
AvahiLookupResultFlags flags, void *userdata)
{
Q_UNUSED(browser)
Q_UNUSED(flags)
AvahiService *service = static_cast<AvahiService *>(userdata);
switch (event) {
case AVAHI_BROWSER_NEW:
qDebug() << "Found Apple device:" << name;
if (!avahi_service_resolver_new(service->m_client, interface, protocol,
name, type, domain, AVAHI_PROTO_UNSPEC,
(AvahiLookupFlags)0, resolveCallback,
userdata)) {
qWarning() << "Failed to create resolver for" << name;
}
break;
case AVAHI_BROWSER_REMOVE:
qDebug() << "Apple device removed:" << name;
emit service->deviceRemoved(QString::fromUtf8(name));
// Remove from our list
{
QMutexLocker locker(&service->m_devicesMutex);
service->m_networkDevices.removeIf(
[name](const NetworkDevice &dev) {
return dev.name == QString::fromUtf8(name);
});
}
break;
case AVAHI_BROWSER_FAILURE:
qWarning() << "Browser failure";
break;
default:
break;
}
}
void AvahiService::resolveCallback(
AvahiServiceResolver *resolver, AvahiIfIndex interface,
AvahiProtocol protocol, AvahiResolverEvent event, const char *name,
const char *type, const char *domain, const char *host_name,
const AvahiAddress *address, uint16_t port, AvahiStringList *txt,
AvahiLookupResultFlags flags, void *userdata)
{
Q_UNUSED(interface)
Q_UNUSED(protocol)
Q_UNUSED(type)
Q_UNUSED(domain)
Q_UNUSED(flags)
AvahiService *service = static_cast<AvahiService *>(userdata);
if (event == AVAHI_RESOLVER_FOUND) {
NetworkDevice device;
device.name = QString::fromUtf8(name);
device.hostname = QString::fromUtf8(host_name);
device.port = port > 0 ? port : 22; // Default to SSH port
// Convert address to string
char addr_str[AVAHI_ADDRESS_STR_MAX];
avahi_address_snprint(addr_str, sizeof(addr_str), address);
device.address = QString::fromUtf8(addr_str);
// Parse TXT records
for (AvahiStringList *t = txt; t; t = t->next) {
char *key = nullptr;
char *value = nullptr;
avahi_string_list_get_pair(t, &key, &value, nullptr);
if (key) {
device.txt[key] = value ? value : "";
avahi_free(key);
}
if (value) {
avahi_free(value);
}
}
qDebug() << "Resolved Apple device:" << device.name << "at"
<< device.address << ":" << device.port;
// Add to our list if not already present
{
QMutexLocker locker(&service->m_devicesMutex);
bool exists = std::any_of(service->m_networkDevices.begin(),
service->m_networkDevices.end(),
[&device](const NetworkDevice &existing) {
return existing == device;
});
if (!exists) {
service->m_networkDevices.append(device);
emit service->deviceAdded(device);
}
}
} else if (event == AVAHI_RESOLVER_FAILURE) {
qWarning() << "Failed to resolve service" << name;
}
avahi_service_resolver_free(resolver);
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef AVAHI_SERVICE_H
#define AVAHI_SERVICE_H
#include <QList>
#include <QMutex>
#include <QObject>
#include <QString>
#include <QThread>
#include <QTimer>
#include <map>
#include <string>
#include <avahi-client/client.h>
#include <avahi-client/lookup.h>
#include <avahi-common/simple-watch.h>
struct NetworkDevice {
QString name; // service name
QString hostname; // e.g., iPhone-2.local
QString address; // IPv4 or IPv6 address
uint16_t port = 22; // SSH port
std::map<std::string, std::string> txt; // TXT records
bool operator==(const NetworkDevice &other) const
{
return name == other.name && address == other.address;
}
};
class AvahiService : public QObject
{
Q_OBJECT
public:
explicit AvahiService(QObject *parent = nullptr);
~AvahiService();
void startBrowsing();
void stopBrowsing();
QList<NetworkDevice> getNetworkDevices() const;
signals:
void deviceAdded(const NetworkDevice &device);
void deviceRemoved(const QString &deviceName);
private slots:
void pollAvahi();
private:
void initializeAvahi();
void cleanupAvahi();
static void clientCallback(AvahiClient *client, AvahiClientState state,
void *userdata);
static void browseCallback(AvahiServiceBrowser *browser,
AvahiIfIndex interface, AvahiProtocol protocol,
AvahiBrowserEvent event, const char *name,
const char *type, const char *domain,
AvahiLookupResultFlags flags, void *userdata);
static void resolveCallback(AvahiServiceResolver *resolver,
AvahiIfIndex interface, AvahiProtocol protocol,
AvahiResolverEvent event, const char *name,
const char *type, const char *domain,
const char *host_name,
const AvahiAddress *address, uint16_t port,
AvahiStringList *txt,
AvahiLookupResultFlags flags, void *userdata);
AvahiSimplePoll *m_simplePoll;
AvahiClient *m_client;
AvahiServiceBrowser *m_serviceBrowser;
QTimer *m_pollTimer;
mutable QMutex m_devicesMutex;
QList<NetworkDevice> m_networkDevices;
bool m_running;
};
#endif // AVAHI_SERVICE_H
+305 -33
View File
@@ -1,15 +1,21 @@
#include "jailbrokenwidget.h"
#include "appcontext.h"
#include "core/services/avahi_service.h"
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include <QButtonGroup>
#include <QDebug>
#include <QGraphicsPixmapItem>
#include <QGraphicsView>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QProcess>
#include <QProcessEnvironment>
#include <QPushButton>
#include <QRadioButton>
#include <QScrollArea>
#include <QTimer>
#include <QVBoxLayout>
#include <QWidget>
@@ -36,10 +42,20 @@ JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
mainLayout->addWidget(graphicsView, 1);
// Connect to AppContext for device events
connect(AppContext::sharedInstance(), &AppContext::deviceAdded, this,
[this](iDescriptorDevice *device) { deviceConnected(device); });
&JailbrokenWidget::onWiredDeviceAdded);
connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
&JailbrokenWidget::onWiredDeviceRemoved);
// Right side: Info and Terminal
// Initialize Avahi service
m_avahiService = new AvahiService(this);
connect(m_avahiService, &AvahiService::deviceAdded, this,
&JailbrokenWidget::onWirelessDeviceAdded);
connect(m_avahiService, &AvahiService::deviceRemoved, this,
&JailbrokenWidget::onWirelessDeviceRemoved);
// Right side: Device selection and Terminal
QWidget *rightContainer = new QWidget();
rightContainer->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
@@ -48,15 +64,7 @@ JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
rightLayout->setContentsMargins(15, 15, 15, 15);
rightLayout->setSpacing(10);
m_infoLabel = new QLabel("Connect a jailbroken device");
rightLayout->addWidget(m_infoLabel);
m_connectButton = new QPushButton("Connect SSH Terminal");
m_connectButton->setEnabled(false);
connect(m_connectButton, &QPushButton::clicked, this,
&JailbrokenWidget::onConnectSSH);
rightLayout->addWidget(m_connectButton);
setupDeviceSelectionUI(rightLayout);
setupTerminal();
rightLayout->addWidget(m_terminal, 1);
@@ -71,6 +79,12 @@ JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
m_sshTimer = new QTimer(this);
connect(m_sshTimer, &QTimer::timeout, this,
&JailbrokenWidget::checkSshData);
// Start scanning for wireless devices
m_avahiService->startBrowsing();
// Populate initial devices
updateDeviceList();
}
void JailbrokenWidget::setupTerminal()
@@ -78,9 +92,228 @@ void JailbrokenWidget::setupTerminal()
m_terminal = new QTermWidget(0, this);
m_terminal->setMinimumHeight(400);
m_terminal->setScrollBarPosition(QTermWidget::ScrollBarRight);
m_terminal->setColorScheme("DarkPastels");
m_terminal->setColorScheme("Linux");
m_terminal->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_terminal, &QWidget::customContextMenuRequested, this,
[this](const QPoint &pos) {
QMenu menu(this);
QList<QAction *> actions = m_terminal->filterActions(pos);
if (!actions.isEmpty()) {
menu.addActions(actions);
menu.exec(m_terminal->mapToGlobal(pos));
}
});
m_terminal->startTerminalTeletype();
m_terminal->hide();
m_terminal->setStyleSheet("padding : 10px;");
}
void JailbrokenWidget::setupDeviceSelectionUI(QVBoxLayout *layout)
{
// Create scroll area for device selection
QScrollArea *scrollArea = new QScrollArea();
scrollArea->setWidgetResizable(true);
scrollArea->setMinimumHeight(200);
scrollArea->setMaximumHeight(300);
QWidget *scrollContent = new QWidget();
m_deviceLayout = new QVBoxLayout(scrollContent);
m_deviceLayout->setContentsMargins(5, 5, 5, 5);
m_deviceLayout->setSpacing(10);
// Button group for device selection
m_deviceButtonGroup = new QButtonGroup(this);
connect(m_deviceButtonGroup,
QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked),
this, &JailbrokenWidget::onDeviceSelected);
// Wired devices group
m_wiredDevicesGroup = new QGroupBox("Connected Devices");
m_wiredDevicesLayout = new QVBoxLayout(m_wiredDevicesGroup);
m_deviceLayout->addWidget(m_wiredDevicesGroup);
// Wireless devices group
m_wirelessDevicesGroup = new QGroupBox("Network Devices");
m_wirelessDevicesLayout = new QVBoxLayout(m_wirelessDevicesGroup);
m_deviceLayout->addWidget(m_wirelessDevicesGroup);
scrollArea->setWidget(scrollContent);
layout->addWidget(scrollArea);
// Info and connect button
m_infoLabel = new QLabel("Select a device to connect");
layout->addWidget(m_infoLabel);
m_connectButton = new QPushButton("Connect SSH Terminal");
m_connectButton->setEnabled(false);
connect(m_connectButton, &QPushButton::clicked, this,
&JailbrokenWidget::onConnectSSH);
layout->addWidget(m_connectButton);
}
void JailbrokenWidget::updateDeviceList()
{
// Clear existing devices
clearDeviceButtons();
// Add wired devices
QList<iDescriptorDevice *> wiredDevices =
AppContext::sharedInstance()->getAllDevices();
for (iDescriptorDevice *device : wiredDevices) {
addWiredDevice(device);
}
// Add wireless devices
QList<NetworkDevice> wirelessDevices = m_avahiService->getNetworkDevices();
for (const NetworkDevice &device : wirelessDevices) {
addWirelessDevice(device);
}
}
void JailbrokenWidget::clearDeviceButtons()
{
// Remove all buttons from button group and layouts
for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
m_deviceButtonGroup->removeButton(button);
button->deleteLater();
}
// Clear layouts
QLayoutItem *item;
while ((item = m_wiredDevicesLayout->takeAt(0)) != nullptr) {
delete item->widget();
delete item;
}
while ((item = m_wirelessDevicesLayout->takeAt(0)) != nullptr) {
delete item->widget();
delete item;
}
}
void JailbrokenWidget::addWiredDevice(iDescriptorDevice *device)
{
QString deviceName = QString::fromStdString(device->deviceInfo.deviceName);
QString udid = QString::fromStdString(device->udid);
QString displayText = QString("%1\n%2").arg(deviceName, udid);
QRadioButton *radioButton = new QRadioButton(displayText);
radioButton->setProperty("deviceType", "wired");
radioButton->setProperty("devicePointer",
QVariant::fromValue(static_cast<void *>(device)));
radioButton->setProperty("udid", udid);
m_deviceButtonGroup->addButton(radioButton);
m_wiredDevicesLayout->addWidget(radioButton);
}
void JailbrokenWidget::addWirelessDevice(const NetworkDevice &device)
{
QString displayText = QString("%1\n%2").arg(device.name, device.address);
QRadioButton *radioButton = new QRadioButton(displayText);
radioButton->setProperty("deviceType", "wireless");
radioButton->setProperty("deviceAddress", device.address);
radioButton->setProperty("deviceName", device.name);
radioButton->setProperty("devicePort", device.port);
m_deviceButtonGroup->addButton(radioButton);
m_wirelessDevicesLayout->addWidget(radioButton);
}
void JailbrokenWidget::onWiredDeviceAdded(iDescriptorDevice *device)
{
addWiredDevice(device);
}
void JailbrokenWidget::onWiredDeviceRemoved(const std::string &udid)
{
QString qudid = QString::fromStdString(udid);
// Find and remove the corresponding radio button
for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
if (button->property("deviceType").toString() == "wired" &&
button->property("udid").toString() == qudid) {
m_deviceButtonGroup->removeButton(button);
button->deleteLater();
break;
}
}
// Reset selection if this device was selected
if (m_selectedDeviceType == DeviceType::Wired && m_selectedWiredDevice &&
m_selectedWiredDevice->udid == udid) {
resetSelection();
}
}
void JailbrokenWidget::onWirelessDeviceAdded(const NetworkDevice &device)
{
addWirelessDevice(device);
}
void JailbrokenWidget::onWirelessDeviceRemoved(const QString &deviceName)
{
// Find and remove the corresponding radio button
for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
if (button->property("deviceType").toString() == "wireless" &&
button->property("deviceName").toString() == deviceName) {
m_deviceButtonGroup->removeButton(button);
button->deleteLater();
break;
}
}
// Reset selection if this device was selected
if (m_selectedDeviceType == DeviceType::Wireless &&
m_selectedNetworkDevice.name == deviceName) {
resetSelection();
}
}
void JailbrokenWidget::onDeviceSelected(QAbstractButton *button)
{
QString deviceType = button->property("deviceType").toString();
if (deviceType == "wired") {
m_selectedDeviceType = DeviceType::Wired;
m_selectedWiredDevice = static_cast<iDescriptorDevice *>(
button->property("devicePointer").value<void *>());
if (m_selectedWiredDevice->deviceInfo.jailbroken) {
m_infoLabel->setText("Jailbroken device selected");
} else {
m_infoLabel->setText("Device selected (jailbreak status unknown)");
}
} else if (deviceType == "wireless") {
m_selectedDeviceType = DeviceType::Wireless;
m_selectedNetworkDevice.name =
button->property("deviceName").toString();
m_selectedNetworkDevice.address =
button->property("deviceAddress").toString();
m_selectedNetworkDevice.port = button->property("devicePort").toUInt();
m_infoLabel->setText(
"Network device selected (jailbreak status unknown)");
}
m_connectButton->setEnabled(true);
m_connectButton->setText("Connect SSH Terminal");
}
void JailbrokenWidget::resetSelection()
{
m_selectedDeviceType = DeviceType::None;
m_selectedWiredDevice = nullptr;
m_selectedNetworkDevice = NetworkDevice{};
m_connectButton->setEnabled(false);
m_infoLabel->setText("Select a device to connect");
// Uncheck all radio buttons
if (m_deviceButtonGroup->checkedButton()) {
m_deviceButtonGroup->setExclusive(false);
m_deviceButtonGroup->checkedButton()->setChecked(false);
m_deviceButtonGroup->setExclusive(true);
}
}
void JailbrokenWidget::connectLibsshToTerminal()
@@ -100,11 +333,14 @@ void JailbrokenWidget::connectLibsshToTerminal()
void JailbrokenWidget::deviceConnected(iDescriptorDevice *device)
{
if (device->deviceInfo.jailbroken) {
m_device = device;
m_infoLabel->setText("Jailbroken device connected");
m_connectButton->setEnabled(true);
m_connectButton->setText("Connect SSH Terminal");
} else {
m_infoLabel->setText(
"Connected device is not detected as jailbroken. Continue anyway?");
}
m_device = device;
m_connectButton->setEnabled(true);
m_connectButton->setText("Connect SSH Terminal");
}
void JailbrokenWidget::onConnectSSH()
@@ -114,24 +350,33 @@ void JailbrokenWidget::onConnectSSH()
return;
}
initWidget();
if (m_selectedDeviceType == DeviceType::None) {
m_infoLabel->setText("Please select a device first");
return;
}
if (m_selectedDeviceType == DeviceType::Wired) {
initWiredDevice();
} else {
initWirelessDevice();
}
}
void JailbrokenWidget::initWidget()
void JailbrokenWidget::initWiredDevice()
{
if (m_isInitialized)
return;
m_isInitialized = true;
if (!m_device) {
m_infoLabel->setText("Device is not jailbroken");
if (!m_selectedWiredDevice) {
m_infoLabel->setText("No wired device selected");
return;
}
m_connectButton->setEnabled(false);
m_infoLabel->setText("Setting up SSH tunnel...");
// Start iproxy first
// Start iproxy first for wired devices
iproxyProcess = new QProcess(this);
iproxyProcess->setProcessChannelMode(QProcess::MergedChannels);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
@@ -147,13 +392,22 @@ void JailbrokenWidget::initWidget()
qDebug() << "iproxy error:" << error;
});
QTimer::singleShot(
3000, this,
&JailbrokenWidget::startSSH); // Increased delay to 3 seconds
// Monitor iproxy output for readiness
connect(iproxyProcess, &QProcess::readyRead, this, [this]() {
QByteArray output = iproxyProcess->readAll();
if (output.contains("waiting for connection")) {
// iproxy is ready, disconnect the signal to avoid multiple calls
disconnect(iproxyProcess, &QProcess::readyRead, this, nullptr);
startSSH("127.0.0.1", 3333);
}
});
iproxyProcess->start("iproxy", QStringList()
<< "-u" << m_device->udid.c_str()
<< "3333" << "22");
QStringList args;
args << "-u" << m_selectedWiredDevice->udid.c_str() << "3333" << "22";
qDebug() << "Starting iproxy with args:" << args;
iproxyProcess->start("iproxy", args);
// Check if iproxy started successfully
if (!iproxyProcess->waitForStarted(5000)) {
@@ -163,13 +417,26 @@ void JailbrokenWidget::initWidget()
}
}
void JailbrokenWidget::startSSH()
void JailbrokenWidget::initWirelessDevice()
{
if (m_isInitialized)
return;
m_isInitialized = true;
m_connectButton->setEnabled(false);
m_infoLabel->setText("Connecting to network device...");
// For wireless devices, connect directly without iproxy
startSSH(m_selectedNetworkDevice.address, m_selectedNetworkDevice.port);
}
void JailbrokenWidget::startSSH(const QString &host, uint16_t port)
{
if (m_sshConnected)
return;
m_infoLabel->setText("Connecting to SSH server...");
qDebug() << "Starting SSH connection to localhost:3333";
qDebug() << "Starting SSH connection to" << host << ":" << port;
// Create SSH session
m_sshSession = ssh_new();
@@ -180,9 +447,10 @@ void JailbrokenWidget::startSSH()
}
// Configure SSH session
ssh_options_set(m_sshSession, SSH_OPTIONS_HOST, "localhost");
int port = 3333;
ssh_options_set(m_sshSession, SSH_OPTIONS_PORT, &port);
QByteArray hostBytes = host.toUtf8();
ssh_options_set(m_sshSession, SSH_OPTIONS_HOST, hostBytes.constData());
int sshPort = static_cast<int>(port);
ssh_options_set(m_sshSession, SSH_OPTIONS_PORT, &sshPort);
ssh_options_set(m_sshSession, SSH_OPTIONS_USER, "root");
// Disable strict host key checking
@@ -345,8 +613,12 @@ void JailbrokenWidget::disconnectSSH()
}
if (iproxyProcess) {
iproxyProcess->terminate();
iproxyProcess->waitForFinished(3000);
iproxyProcess->terminate(); // Ask it to terminate nicely
if (!iproxyProcess->waitForFinished(1000)) { // Wait 1 sec
iproxyProcess->kill(); // Forcefully kill it
iproxyProcess->waitForFinished(1000); // Wait for it to die
}
delete iproxyProcess; // Avoid memory leak
iproxyProcess = nullptr;
}
+51 -14
View File
@@ -1,50 +1,87 @@
#ifndef JAILBROKENWIDGET_H
#define JAILBROKENWIDGET_H
#include "core/services/avahi_service.h"
#include "iDescriptor.h"
#include <QAbstractButton>
#include <QButtonGroup>
#include <QGroupBox>
#include <QLabel>
#include <QProcess>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
#include <QWidget>
#include <libssh/libssh.h>
#include <qtermwidget6/qtermwidget.h>
class QTermWidget;
enum class DeviceType { None, Wired, Wireless };
class JailbrokenWidget : public QWidget
{
Q_OBJECT
public:
explicit JailbrokenWidget(QWidget *parent = nullptr);
JailbrokenWidget(QWidget *parent = nullptr);
~JailbrokenWidget();
void initWidget();
private slots:
void deviceConnected(iDescriptorDevice *device);
void onConnectSSH();
void startSSH();
void checkSshData();
void onWiredDeviceAdded(iDescriptorDevice *device);
void onWiredDeviceRemoved(const std::string &udid);
void onWirelessDeviceAdded(const NetworkDevice &device);
void onWirelessDeviceRemoved(const QString &deviceName);
void onDeviceSelected(QAbstractButton *button);
private:
void setupTerminal();
void connectLibsshToTerminal();
void setupDeviceSelectionUI(QVBoxLayout *layout);
void updateDeviceList();
void clearDeviceButtons();
void addWiredDevice(iDescriptorDevice *device);
void addWirelessDevice(const NetworkDevice &device);
void resetSelection();
void initWiredDevice();
void initWirelessDevice();
void startSSH(const QString &host, uint16_t port);
void disconnectSSH();
void connectLibsshToTerminal();
void deviceConnected(iDescriptorDevice *device);
QTermWidget *m_terminal;
QLabel *m_infoLabel;
iDescriptorDevice *m_device = nullptr;
QProcess *iproxyProcess = nullptr;
QPushButton *m_connectButton;
// SSH session variables
// Device selection UI
QVBoxLayout *m_deviceLayout;
QGroupBox *m_wiredDevicesGroup;
QGroupBox *m_wirelessDevicesGroup;
QVBoxLayout *m_wiredDevicesLayout;
QVBoxLayout *m_wirelessDevicesLayout;
QButtonGroup *m_deviceButtonGroup;
// Avahi service for network discovery
AvahiService *m_avahiService;
// Selected device tracking
DeviceType m_selectedDeviceType = DeviceType::None;
iDescriptorDevice *m_selectedWiredDevice = nullptr;
NetworkDevice m_selectedNetworkDevice;
// Legacy device pointer (kept for compatibility)
iDescriptorDevice *m_device = nullptr;
// SSH components
ssh_session m_sshSession;
ssh_channel m_sshChannel;
QTimer *m_sshTimer;
QProcess *iproxyProcess = nullptr;
// Terminal widgets
QTermWidget *m_terminal;
QPushButton *m_connectButton;
bool m_isInitialized = false;
bool m_sshConnected = false;
bool m_isInitialized = false;
};
#endif // JAILBROKENWIDGET_H