From fd508acfe2c02150878fca10872ebc8a4850027b Mon Sep 17 00:00:00 2001 From: uncor3 Date: Tue, 7 Apr 2026 18:26:59 +0000 Subject: [PATCH] refactor(diagnosewidget): update service availability checks, D-Bus integration --- CMakeLists.txt | 8 ++ src/diagnosewidget.cpp | 169 +++++++++++++++++++++-------------------- src/diagnosewidget.h | 9 ++- src/service.h | 3 +- 4 files changed, 105 insertions(+), 84 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cffcee3..3e39143 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,10 @@ endif() find_package(PkgConfig REQUIRED) find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets Network QuickControls2 SerialPort Positioning Location QuickWidgets) +# DBUS +if (UNIX AND NOT APPLE) + find_package(Qt6 REQUIRED COMPONENTS DBus) +endif() find_package(SQLite3 REQUIRED) # Add QTermWidget # Prefer CMake-native qtermwidget6, fallback to pkg-config if needed @@ -297,6 +301,10 @@ target_link_libraries(iDescriptor PRIVATE SQLite::SQLite3 ) +if (UNIX AND NOT APPLE) + target_link_libraries(iDescriptor PRIVATE Qt6::DBus) +endif() + if(ENABLE_RECOVERY_DEVICE_SUPPORT) target_link_libraries(iDescriptor PRIVATE ${IRECOVERY_LIBRARY}) target_compile_definitions(iDescriptor PRIVATE ENABLE_RECOVERY_DEVICE_SUPPORT) diff --git a/src/diagnosewidget.cpp b/src/diagnosewidget.cpp index 9be95c5..bd4ed14 100644 --- a/src/diagnosewidget.cpp +++ b/src/diagnosewidget.cpp @@ -83,10 +83,9 @@ void DependencyItem::setInstalled(SERVICE_AVAILABILITY availability, setChecking(false); m_availability = availability; - const bool isInstalled = (availability != SERVICE_UNAVAILABLE); - const bool isRunning = (availability == SERVICE_AVAILABLE); - - if (isRunning) { + switch (availability) { + case SERVICE_AVAILABLE: + /* code */ if (m_name == "Avahi Daemon" || m_name == "Bonjour Service") { m_statusLabel->setText("Activated"); } else { @@ -103,25 +102,25 @@ void DependencyItem::setInstalled(SERVICE_AVAILABILITY availability, #endif m_installButton->setVisible(false); return; - } + break; - // Not running or not installed - if (isInstalled) { - // Installed but not running (only meaningful for services) + case SERVICE_AVAILABLE_BUT_NOT_RUNNING: m_statusLabel->setText("Installed but not running"); m_installButton->setText("Enable"); - } else { - if (m_name == "Avahi Daemon") { - m_statusLabel->setText("Not activated"); - m_installButton->setText("Enable"); + break; + case UNABLE_TO_CHECK: + m_statusLabel->setText("Action needed"); + m_installButton->setText("Info"); + break; + case SERVICE_UNAVAILABLE: + if (isRequired) { + m_statusLabel->setText("Not Installed"); } else { - if (isRequired) { - m_statusLabel->setText("Not Installed"); - } else { - m_statusLabel->setText("Not Installed (Optional)"); - } - m_installButton->setText("Install"); + m_statusLabel->setText("Not Installed (Optional)"); } + break; + default: + break; } #ifndef WIN32 @@ -203,14 +202,12 @@ DiagnoseWidget::DiagnoseWidget(QWidget *parent) #endif #ifdef __linux__ + addDependencyItem("Avahi Daemon", "Required for AirPlay, wireless devices"); #ifdef ENABLE_RECOVERY_DEVICE_SUPPORT addDependencyItem("UDEV rules", "Required for recovery devices requires manual setup", true); #endif - addDependencyItem( - "Avahi Daemon", - "Required for Airplay, wireless devices and network service discovery"); #endif // Auto-check on startup @@ -538,67 +535,64 @@ void DiagnoseWidget::onInstallRequested(const QString &name) } if (name == "Avahi Daemon") { - DependencyItem *itemToInstall = nullptr; - for (DependencyItem *item : m_dependencyItems) { - if (item->property("name").toString() == name) { - itemToInstall = item; - break; - } - } - - if (!itemToInstall) - return; - - itemToInstall->setInstalling(true); - - QProcess *installProcess = new QProcess(this); - connect( - installProcess, &QProcess::finished, this, - [this, installProcess, - itemToInstall](int exitCode, QProcess::ExitStatus exitStatus) { - if (exitStatus != QProcess::NormalExit || exitCode != 0) { - QString errorOutput = - installProcess->readAllStandardError(); - if (errorOutput.isEmpty()) { - errorOutput = installProcess->readAllStandardOutput(); + if (availability == SERVICE_AVAILABLE_BUT_NOT_RUNNING) { + QProcess *installProcess = new QProcess(this); + connect( + installProcess, &QProcess::finished, this, + [this, installProcess, + itemToInstall](int exitCode, QProcess::ExitStatus exitStatus) { + if (exitStatus != QProcess::NormalExit || exitCode != 0) { + QString errorOutput = + installProcess->readAllStandardError(); + if (errorOutput.isEmpty()) { + errorOutput = + installProcess->readAllStandardOutput(); + } + QMessageBox::warning(this, "Error", + "Failed to enable Avahi daemon. " + "This might be because the action " + "was cancelled or an " + "error occurred.\n\nDetails: " + + errorOutput.trimmed()); + checkDependencies(false); + } else { + checkDependencies(false); } - QMessageBox::warning( - this, "Error", - "Failed to enable Avahi daemon. " - "This might be because the action was cancelled or an " - "error occurred.\n\nDetails: " + - errorOutput.trimmed()); - checkDependencies(false); - } else { - checkDependencies(false); - } - itemToInstall->setInstalling(false); - installProcess->deleteLater(); - }); + itemToInstall->setInstalling(false); + installProcess->deleteLater(); + }); - QStringList args; - args << "systemctl" - << "enable" - << "--now" - << "avahi-daemon.service"; - installProcess->start("pkexec", args); + QStringList args; + args << "systemctl" + << "enable" + << "--now" + << "avahi-daemon.service"; + installProcess->start("pkexec", args); + return; + } + QMessageBox::information(this, "Avahi Daemon", + "The Avahi daemon is responsible for network " + "service discovery and is required for " + "AirPlay and wireless device features.\n\n" + "Please use your distribution's package " + "manager to install 'avahi'"); } #endif } #ifdef __linux__ -bool DiagnoseWidget::checkUdevRulesInstalled() +SERVICE_AVAILABILITY DiagnoseWidget::checkUdevRulesInstalled() { // Check if udev rules file exists QFile rulesFile("/etc/udev/rules.d/99-idevice.rules"); if (!rulesFile.exists()) { - return false; + return UNABLE_TO_CHECK; } // Check if the file contains the correct rule if (!rulesFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; + return UNABLE_TO_CHECK; } QTextStream in(&rulesFile); @@ -611,7 +605,7 @@ bool DiagnoseWidget::checkUdevRulesInstalled() bool hasMode = content.contains("MODE=\"0666\""); if (!hasUsbSubsystem || !hasAppleVendor || !hasMode) { - return false; + return UNABLE_TO_CHECK; } // Check if current user is in the idevice group @@ -621,7 +615,7 @@ bool DiagnoseWidget::checkUdevRulesInstalled() if (groupsProcess.exitCode() != 0) { // If we can't check groups, consider it not installed - return false; + return UNABLE_TO_CHECK; } QString groupsOutput = @@ -630,24 +624,37 @@ bool DiagnoseWidget::checkUdevRulesInstalled() groupsOutput.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); bool isInIdeviceGroup = groups.contains("idevice"); - - return isInIdeviceGroup; + qDebug() << "Is user in 'idevice' group?" << isInIdeviceGroup; + return isInIdeviceGroup ? SERVICE_AVAILABLE : UNABLE_TO_CHECK; } -bool DiagnoseWidget::checkAvahiDaemonRunning() +SERVICE_AVAILABILITY DiagnoseWidget::checkAvahiDaemonRunning() { - QProcess checkProcess; - checkProcess.start("systemctl", QStringList() - << "is-active" << "avahi-daemon"); - checkProcess.waitForFinished(3000); - - if (checkProcess.exitCode() != 0) { - return false; + // Connect to the system bus + QDBusConnection systemBus = QDBusConnection::systemBus(); + if (!systemBus.isConnected()) { + return UNABLE_TO_CHECK; } - QString output = - QString::fromUtf8(checkProcess.readAllStandardOutput()).trimmed(); - return output == "active"; + QDBusConnectionInterface *iface = systemBus.interface(); + if (!iface) { + return UNABLE_TO_CHECK; + } + + // Avahi daemon D-Bus name + const QString avahiService = QStringLiteral("org.freedesktop.Avahi"); + + // If the service is registered, Avahi is running + if (iface->isServiceRegistered(avahiService).value()) { + return SERVICE_AVAILABLE; + } + + // maybe installed ? + bool hasBinary = + !QStandardPaths::findExecutable(QStringLiteral("avahi-browse")) + .isEmpty(); + + return hasBinary ? SERVICE_AVAILABLE_BUT_NOT_RUNNING : SERVICE_UNAVAILABLE; } #endif diff --git a/src/diagnosewidget.h b/src/diagnosewidget.h index c141014..dcc6c53 100644 --- a/src/diagnosewidget.h +++ b/src/diagnosewidget.h @@ -48,6 +48,11 @@ #include #include #include +#ifdef __linux__ +#include +#include +#include +#endif #include "service.h" @@ -106,8 +111,8 @@ private: #endif #ifdef __linux__ - bool checkUdevRulesInstalled(); - bool checkAvahiDaemonRunning(); + SERVICE_AVAILABILITY checkUdevRulesInstalled(); + SERVICE_AVAILABILITY checkAvahiDaemonRunning(); #endif QVBoxLayout *m_mainLayout; diff --git a/src/service.h b/src/service.h index 08db589..25df869 100644 --- a/src/service.h +++ b/src/service.h @@ -2,5 +2,6 @@ enum SERVICE_AVAILABILITY { SERVICE_AVAILABLE, SERVICE_AVAILABLE_BUT_NOT_RUNNING, - SERVICE_UNAVAILABLE + SERVICE_UNAVAILABLE, + UNABLE_TO_CHECK }; \ No newline at end of file