/*! * * Copyright (c) 2021-2025 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file WifiInterface.cpp * \author (last) Behrouz NematiPour * \date (last) 26-Sep-2024 * \author (original) Behrouz NematiPour * \date (original) 11-May-2021 * */ #include "WifiInterface.h" // Qt #include #include #include #include // Project #include "main.h" #include "Logger.h" using namespace Storage; WifiInterface::WifiInterface(QObject *parent) : QObject(parent) { _processScan .setParent(this); _processDisconnectNetwork .setParent(this); _processReadIPSettings .setParent(this); _processReadGateway .setParent(this); _processReadDNS .setParent(this); _processGenerateWPASupplicant .setParent(this); _processStartWPASupplicant .setParent(this); _processRequestAutoAssignedIP .setParent(this); _processSetStaticIPAddress .setParent(this); _processSetStaticGateway .setParent(this); _processSetStaticSubnetMask .setParent(this); _processSetDNS .setParent(this); _processReadNetworkInfo .setParent(this); } /*! * \brief WifiInterface::hasConnectedToWifi * Checks whether we have previously connected to a WiFi network * \return (bool) true if we have, false otherwise */ bool WifiInterface::hasConnectedToWifi() { if (!QFile(_wpaSupplicantConfPath).exists()) return false; return true; } /*! * \brief WifiInterface::rejoinLastWifiNetwork * Attempts to rejoin the network we last connected to */ void WifiInterface::rejoinLastWifiNetwork() { if (_processStartWPASupplicant.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processStartWPASupplicant.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Start_WPA_Supplicant) ) return; _processStartWPASupplicant.start(script, QStringList() << iface() << _wpaSupplicantConfPath); } void WifiInterface::initConnections() { connect(this, SIGNAL(didStatusChanged(const QString)), this, SLOT( onStatusChanged(const QString))); connect(this, SIGNAL( didError(const QString)), this, SLOT( onStatusChanged(const QString))); connect(&_processScan , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedScan(int, QProcess::ExitStatus))); connect(&_processReadIPSettings , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedReadIP(int, QProcess::ExitStatus))); connect(&_processReadGateway , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedReadGateway(int, QProcess::ExitStatus))); connect(&_processReadDNS , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedReadDNS(int, QProcess::ExitStatus))); connect(&_processGenerateWPASupplicant , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedGenerateWPASupplicant(int, QProcess::ExitStatus))); connect(&_processStartWPASupplicant , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedStartWPASupplicant(int, QProcess::ExitStatus))); connect(&_processRequestAutoAssignedIP , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedRequestAutoAssignedIP(int, QProcess::ExitStatus))); connect(&_processDisconnectNetwork , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedDisconnectNetwork(int, QProcess::ExitStatus))); connect(&_processSetStaticIPAddress , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedSetIPAddress(int, QProcess::ExitStatus))); connect(&_processReadNetworkInfo , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedReadNetworkInfo(int, QProcess::ExitStatus))); connect(&_processSetStaticGateway , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedSetGateway(int, QProcess::ExitStatus))); connect(&_processSetStaticSubnetMask , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedSetSubnetMask(int, QProcess::ExitStatus))); connect(&_processSetDNS , SIGNAL( finished(int, QProcess::ExitStatus)), this , SLOT( onProcessFinishedSetDNS(int, QProcess::ExitStatus))); connect(this , SIGNAL( didRequestAutoAssignedIP()), this , SLOT( onRequestAutoAssignedIP())); } /*! * \brief WifiInterface::init * \details Initialized the Class by calling the init() method first * And initializes the thread vThread by calling initThread * on success init(). * \param vThread - the thread * \return returns the return value of the init() method */ bool WifiInterface::init(QThread &vThread) { if (!init()) return false; initThread(vThread); return true; } /*! * \brief ApplicationController::initThread * \details Moves this object into the thread vThread. * And checks that this method is called from main thread. * Also connects quitThread to application aboutToQuit. * \param vThread - the thread */ void WifiInterface::initThread(QThread &vThread) { // runs in main thread Q_ASSERT_X(QThread::currentThread() == qApp->thread() , __func__, "The Class initialization must be done in Main Thread" ); _thread = &vThread; _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); _thread->start(); moveToThread(_thread); } /*! * \brief MessageAcknowModel::quit * \details quits the class * Calls quitThread */ void WifiInterface::quit() { // disabled coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. quitThread(); } // disabled coco end /*! * \brief MessageAcknowModel::quitThread * \details Moves this object to main thread to be handled by QApplication * And to be destroyed there. */ void WifiInterface::quitThread() { // disabled coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. if (!_thread) return; // runs in thread moveToThread(qApp->thread()); } // disabled coco end /*! * \brief WifiInterface::init * \details Initializes the class by setting the connections * \return true on first initialization, false if it has already been initialized */ bool WifiInterface::init() { if (_init) return false; _init = true; initConnections(); LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); return true; } /*! * \brief WifiInterface::ondoStart * Starts the WifiInterface */ void WifiInterface::ondoStart() { if (hasConnectedToWifi()) rejoinLastWifiNetwork(); } /*! * \brief WifiInterface::doScan * Scans for WiFi Access Points */ void WifiInterface::doScan() { if (_scanRunning) { LOG_DEBUG("WiFi network scan is already running."); return; } if (_processScan.state() != QProcess::NotRunning) { LOG_DEBUG("The Running WiFi Scan Ignored."); return; } QString script; if ( ! checkScript(script, Wifi_Scan_For_Networks) ) return; _scanRunning = true; emit didScanStatusChanged(_scanRunning); _processScan.start(script, QStringList() << iface()); LOG_DEBUG("WiFi Scan Started"); } /*! * \brief WifiInterface::onScanFinished * Called when the scan process has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedScan(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitCode) Q_UNUSED(vExitStatus) QString out = _processScan.readAllStandardOutput(); QString err = _processScan.readAllStandardError(); LOG_DEBUG(QString("stdout: %1").arg(out)); LOG_DEBUG(QString("stderr: %1").arg(err)); _scanRunning = false; emit didScanStatusChanged(_scanRunning); QList networks = parseWifiScan(out); // A non-empty macAddress indicates UI is connected to a network // if the network security type list is empty, this indicates that the connection // was a result of a start-up reconnection. Traverse through discovered networks // and update the security type list and signal strength info if(!_network.macAddress().isEmpty() && _network.securityTypes().isEmpty()) { foreach(WifiNetworkData network, networks){ if(network.macAddress() == _network.macAddress()){ // update the security and signal info _network.securityTypes(network.securityTypes()); _network.signalLevel(network.signalLevel()); emit didConnectToNetwork(_network); } } } LOG_DEBUG("WiFi Scan Finished"); } /*! * \brief getTextBetweenDelimiters * Gets the text between two delimiters * \param vText - (QString) the text to search * \param vLeftDelim - (QString) the left delimiter * \param vRightDelim - (QString) the right delimiter * \return (QString) the text between the delimiters if found, "" otherwise */ QString WifiInterface::getTextBetweenDelimiters(const QString &vText, const QString &vLeftDelim, const QString &vRightDelim) { QString result = ""; QString rightHalf = ""; QStringList tokenList = vText.split(vLeftDelim); if (tokenList.length() > 1) rightHalf = tokenList[1]; tokenList = rightHalf.split(vRightDelim); if (tokenList.length() > 1) result = tokenList[0]; return result; } /*! * \brief Network::parseWifiScan * Extract desired information from the WiFi scan output. Sorts by signal stength * * \param vOutput - (QString) output collected from QProcess execution */ QList WifiInterface::parseWifiScan(const QString &vOutput) { QList networks; QString outputNoReturns = vOutput; outputNoReturns = outputNoReturns.replace("\r", ""); QStringList temp = outputNoReturns.split("Cell"); const QString searchTermSignalLevel = "Signal level="; const QString searchTermMacAddress = "Address:"; const QString searchTermSSID = "ESSID:"; for (const QString &cell : temp) { if (cell.contains(searchTermSSID) && cell.contains(searchTermMacAddress) && cell.contains(searchTermSignalLevel)) { QString ssid = getTextBetweenDelimiters(cell, searchTermSSID, "\n").replace("\"", "").trimmed(); if (ssid == "") continue; QString macAddress = getTextBetweenDelimiters(cell, searchTermMacAddress, "\n").trimmed(); int signalLevel = getTextBetweenDelimiters(cell, searchTermSignalLevel, "dBm").trimmed().toInt(); QList securityTypes; bool requiresKey = QRegularExpression("Encryption key:on").match(cell).hasMatch(); QStringList infoElements = cell.split("IE: "); infoElements.takeFirst(); // remove the header for (const QString &element : infoElements) { if ( element.startsWith("Unknown:") ) continue; bool isWPA2 = QRegularExpression(".*WPA2 ").match(element).hasMatch(); bool isWPA = QRegularExpression(".*WPA ").match(element).hasMatch(); bool supportsAES = QRegularExpression("Pairwise Ciphers.*CCMP").match(element).hasMatch(); bool requiresPSK = QRegularExpression("Authentication Suites.*PSK").match(element).hasMatch(); bool supportsTKIP = QRegularExpression("Pairwise Ciphers.*TKIP").match(element).hasMatch(); // NOTE: the iwlist command does not have the SAE and displayes it as unknown but the (8) is the SAE which comes from the driver. bool isWPA3Only = false; bool supportsSAE = QRegularExpression("Authentication Suites.*unknown \\(8\\)").match(element).hasMatch(); // NOTE: if it only supports SAE it means that is the WPA3-only // NOTE: iwlist is not reporting the WPA3 SSID as WPA3 so the only indication is the SAE which belongs only to WPA3. // IMPORTANT: ******************************************************************* // NOTE: we do not support the OWE and ENTERPRISE yet and it is personal for now. // ****************************************************************************** if ( supportsSAE ) { isWPA3Only = QRegularExpression("Authentication Suites \\(1\\) : unknown \\(8\\)").match(element).hasMatch(); } //DEBUG:qDebug() << element << supportsSAE; MWifiNetwork::SECURITY_TYPE securityType = MWifiNetwork::SECURITY_TYPE::UNSUPPORTED; // NOTE: order of the if is very IMPORTANT if ( supportsSAE ) // the wpa3 has the highest priority, and if supported we connect with wpa3 securityType = isWPA3Only ? MWifiNetwork::SECURITY_TYPE::WPA3_SAE_ONLY: MWifiNetwork::SECURITY_TYPE::WPA3_WPA2_TRNS; else if (isWPA2 && requiresPSK && supportsAES && !supportsTKIP) securityType = MWifiNetwork::SECURITY_TYPE::WPA2_AES; else if (isWPA && requiresPSK && supportsAES && supportsTKIP) securityType = MWifiNetwork::SECURITY_TYPE::WPA_TKIP_AES; else if (isWPA && requiresPSK && supportsTKIP) securityType = MWifiNetwork::SECURITY_TYPE::WPA_TKIP; else if (isWPA && requiresPSK && supportsAES) securityType = MWifiNetwork::SECURITY_TYPE::WPA_AES; else if (!isWPA && !isWPA2 && !requiresPSK && !supportsAES && !supportsTKIP && requiresKey) securityType = MWifiNetwork::SECURITY_TYPE::WEP; if (securityType != MWifiNetwork::SECURITY_TYPE::UNSUPPORTED) securityTypes.append(securityType); } // if no type can be found. // we assume it was WEP which we don't support anyway. if ( securityTypes.isEmpty() ) { securityTypes.append(MWifiNetwork::SECURITY_TYPE::WEP); } //DEBUG:qDebug() << macAddress << ssid << securityTypes << signalLevel << requiresKey; WifiNetworkData network(macAddress, ssid, securityTypes, MWifiNetwork::STATUS::NOT_CONNECTED, signalLevel, requiresKey); networks.append(network); emit didAddNetwork(network); } } LOG_DEBUG(QString("WifiInterface::%1 Finished").arg(__FUNCTION__)); return networks; } /*! * \brief WifiInterface::onStatusChanged * Ensures any status changes are logged * \param vMessage (QString) the message detail */ void WifiInterface::onStatusChanged(const QString &vMessage) { LOG_DEBUG(vMessage); } /*! * \brief WifiInterface::doJoinNetwork * Handles request to join a network * \param vMacAddress - (QString) the mac address of the network to join * \param vPassword - (QString) the password for the network provided by the user */ void WifiInterface::doJoinNetwork(const WifiNetworkData &vNetwork, const QString &vPassword) { _network = vNetwork; _useDHCP = true; LOG_DEBUG(QString("Joining Network %1").arg(vNetwork.ssid())); if (_processGenerateWPASupplicant.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processGenerateWPASupplicant.objectName())); return; } QString securityType; if (vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WPA3_WPA2_TRNS) || vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WPA3_SAE_ONLY)) securityType = "wpa3"; else if (vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WPA2_AES)) securityType = "wpa2"; else if (vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WPA_TKIP_AES) || vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WPA_AES) || vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WPA_TKIP)) securityType = "wpa"; else if (vNetwork.securityTypes().contains(MWifiNetwork::SECURITY_TYPE::WEP)) securityType = "wep"; else { LOG_DEBUG(QString("Network %1 has an unsupported security type.").arg(vNetwork.ssid())); emit didError(QString("Network %1 has an unsupported security type.").arg(vNetwork.ssid())); } QString script; if ( ! checkScript(script, Wifi_Generate_WPA_Supplicant) ) return; _processGenerateWPASupplicant.start(script, QStringList() << vNetwork.ssid() << vPassword << iface() << securityType); } /*! * \brief WifiInterface::onProcessFinishedGenerateWPASupplicant * Called when the process that generates the WPA supplicant file has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedGenerateWPASupplicant(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError("Could not configure network."); return; } if (_processStartWPASupplicant.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processStartWPASupplicant.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Start_WPA_Supplicant) ) return; _processStartWPASupplicant.start(script, QStringList() << iface() << _wpaSupplicantConfPath); } /*! * \brief WifiInterface::onProcessFinishedStartWPASupplicant * Called when the process that starts the WPA supplicant has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedStartWPASupplicant(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError("Could not configure network."); return; } emit didRequestAutoAssignedIP(); } /*! * \brief WifiInterface::onRequestAutoAssignedIP * Handles the request for an auto assigned IP address */ void WifiInterface::onRequestAutoAssignedIP() { if (_processRequestAutoAssignedIP.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processRequestAutoAssignedIP.objectName())); return; } QString progressDot = QString(".").repeated(_dhcpAttempts - _dhcpAttemptsLeft); emit didStatusChanged(tr("%1.Obtaining IP Address.%1").arg(progressDot)); QString script; if ( ! checkScript(script, Wifi_Get_Auto_Assigned_IP) ) return; _processRequestAutoAssignedIP.start(script, QStringList() << iface()); } /*! * \brief WifiInterface::onProcessFinishedRequestAutoAssignedIP * Called when the process that requests an auto-assigned IP has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedRequestAutoAssignedIP(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { if (_dhcpAttemptsLeft > 0) { _dhcpAttemptsLeft--; emit didRequestAutoAssignedIP(); } else { emit didError(QString("Could not connect to %1").arg(_network.ssid())); _dhcpAttemptsLeft = _dhcpAttempts; } return; } _dhcpAttemptsLeft = _dhcpAttempts; doRequestIPSettings(); } /*! * \brief WifiInterface::doRequestIPSettings * Handles a request to read the IP settings of the device. */ void WifiInterface::doRequestIPSettings() { if (_processReadIPSettings.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processReadIPSettings.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Read_IP_Settings) ) return; _processReadIPSettings.start(script, QStringList() << iface()); } /*! * \brief WifiInterface::runProcessGetNetworkInfo * Handles a request to read the network info (ssid + macAddress) */ void WifiInterface::runProcessGetNetworkInfo() { if (_processReadNetworkInfo.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processReadNetworkInfo.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Read_Network_Info) ) return; _processReadNetworkInfo.start(script, QStringList() << iface()); } /*! * \brief WifiInterface::onProcessFinishedReadIP * Parses the IP settings of the device when the process has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedReadIP(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitCode); Q_UNUSED(vExitStatus); QString output = _processReadIPSettings.readAllStandardOutput(); _network.mIPSettings.mIPAddress = parseIP(output); _network.mIPSettings.mBroadcast = parseBroadcast(output); _network.mIPSettings.mSubnetMask = parseSubnetMask(output); runProcessGetNetworkInfo(); } /*! * \brief WifiInterface::onProcessFinishedReadNetworkInfo * Parses the network mac address of the device when the process has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedReadNetworkInfo(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitCode); Q_UNUSED(vExitStatus); QString output = _processReadNetworkInfo.readAllStandardOutput(); const QString networkMacAddress = parseNetworkMacAddress(output); _network.macAddress(networkMacAddress.trimmed()); const QString networkSSid = parseNetworkSSID(output); _network.ssid(networkSSid.trimmed()); LOG_DEBUG(QString("Network SSID : '%1' MacAddress: '%2'.") .arg(networkSSid) .arg(networkMacAddress)); if (_processReadGateway.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processReadGateway.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Read_Gateway) ) return; _processReadGateway.start(script, QStringList()); } /*! * \brief WifiInterface::onProcessFinishedReadGateway * Parses the gateway of the device when the process has finished then * initiates reading the DNS * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedReadGateway(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitCode); Q_UNUSED(vExitStatus); _network.mIPSettings.mGateway = parseGateway(_processReadGateway.readAllStandardOutput()); if (_processReadDNS.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processReadDNS.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Read_DNS) ) return; _processReadDNS.start(script, QStringList()); } /*! * \brief WifiInterface::onProcessFinishedReadDNS * Parses the DNS of the device when the process has finished then * emits the newtwork with all the ip address information filled * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedReadDNS(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitCode); Q_UNUSED(vExitStatus); _network.mIPSettings.mDNS = parseDNS(_processReadDNS.readAllStandardOutput()); if (!_useDHCP) { // Use current static IP settings defaults doRequestSetIPAddress(_network.mIPSettings.mIPAddress); doRequestSetGateway(_network.mIPSettings.mGateway); doRequestSetSubnetMask(_network.mIPSettings.mSubnetMask); doRequestSetDNS(_network.mIPSettings.mDNS); } emit didConnectToNetwork(_network); } /*! * \brief WifiInterface::doDisconnectNetwork * Disconnects from the specified network * \param vNetwork - (Network) the network to disconnect from */ void WifiInterface::doDisconnectNetwork(const WifiNetworkData &vNetwork) { LOG_DEBUG(QString("Disconnecting from Network %1").arg(vNetwork.ssid())); if (_processDisconnectNetwork.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processDisconnectNetwork.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Disconnect_Network) ) return; _processDisconnectNetwork.start(script, QStringList() << iface()); } /*! * \brief WifiInterface::onProcessFinishedDisconnectNetwork * Called when we disconnect from the WiFi network * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedDisconnectNetwork(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError(tr("Failed to disconnect from %1").arg(_network.ssid())); return; } emit didDisconnectNetwork(_network); _network.clearSettings(); } /*! * \brief WifiInterface::parseIP * Parses the IP from the IP address output * \param vOutput - (QString) the console output * \return (QString) the IP Address only */ QString WifiInterface::parseIP(const QString &vOutput) { const QString leftDelim = "inet addr:"; const QString rightDelim = "Bcast:"; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::parseBroadcast * Parses the Broadcast from the IP address output * \param vOutput - (QString) the console output * \return (QString) the Broadcast IP if found, "" otherwise */ QString WifiInterface::parseBroadcast(const QString &vOutput) { const QString leftDelim = "Bcast:"; const QString rightDelim = "Mask:"; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::parseSubnetMask * Parses the subnet mask from the provided output * \param vOutput - (QString) the console output * \return (QString) the subnet mask if found, "" otherwise */ QString WifiInterface::parseSubnetMask(const QString &vOutput) { const QString leftDelim = "Mask:"; const QString rightDelim = "\n"; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::parseNetworkMacAddress * Parses the network macAddress from the provided output * \param vOutput - (QString) the console output * \return (QString) the subnet mask if found, "" otherwise */ QString WifiInterface::parseNetworkMacAddress(const QString &vOutput) { const QString leftDelim = "Access Point:"; const QString rightDelim = "Bit Rate="; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::parseNetworkSSID * Parses the network ssid from the provided output * \param vOutput - (QString) the console output * \return (QString) the subnet mask if found, "" otherwise */ QString WifiInterface::parseNetworkSSID(const QString &vOutput) { const QString leftDelim = "ESSID:\""; const QString rightDelim = "\""; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::parseGateway * Parses the gateway from the provided output * \param vOutput - (QString) the console output * \return (QString) the gateway if found, "" otherwise */ QString WifiInterface::parseGateway(const QString &vOutput) { const QString leftDelim = "default via"; const QString rightDelim = "dev"; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::parseDNS * Parses the DNS from the provided output * \param vOutput - (QString) the console output * \return (QString) the first DNS found, "" otherwise */ QString WifiInterface::parseDNS(const QString &vOutput) { const QString leftDelim = "nameserver"; const QString rightDelim = "\n"; return getTextBetweenDelimiters(vOutput, leftDelim, rightDelim); } /*! * \brief WifiInterface::doRequestSetIPAddress * Issues command to set a static IP address * \param vIPAddress - (QString) the IP address */ void WifiInterface::doRequestSetIPAddress(const QString &vIPAddress) { Q_UNUSED(vIPAddress) LOG_DEBUG(QString("Handling request to set static IP address: %1").arg(vIPAddress)); if (_processSetStaticIPAddress.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processSetStaticIPAddress.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Set_Static_IP) ) return; _useDHCP = false; _processSetStaticIPAddress.start(script, QStringList() << iface() << vIPAddress); } /*! * \brief WifiInterface::onProcessFinishedSetIPAddress * Called when settings a static IP address finishes * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedSetIPAddress(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError(tr("Failed to set static IP Address")); return; } emit didSetStaticIPAddress(); } /*! * \brief WifiInterface::doRequestSetGateway * Issues command to set a static gateway * \param vGateway - (QString) the gateway */ void WifiInterface::doRequestSetGateway(const QString &vGateway) { Q_UNUSED(vGateway) LOG_DEBUG(QString("Handling request to set static gateway: %1").arg(vGateway)); if (_processSetStaticGateway.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processSetStaticGateway.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Set_Gateway) ) return; _useDHCP = false; _processSetStaticGateway.start(script, QStringList() << vGateway); } /*! * \brief WifiInterface::onProcessFinishedSetGateway * Called when the the process to set the gateway has finished * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedSetGateway(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError(tr("Failed to set gateway.")); return; } emit didSetGateway(); } /*! * \brief WifiInterface::doRequestSetSubnetMask * Issues command to set the subnet mask * \param vSubnetMask - (QString) the subnet mask */ void WifiInterface::doRequestSetSubnetMask(const QString &vSubnetMask) { Q_UNUSED(vSubnetMask) LOG_DEBUG(QString("Handling request to set static subnet mask: %1").arg(vSubnetMask)); if (_processSetStaticSubnetMask.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processSetStaticSubnetMask.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Set_SubnetMask) ) return; _useDHCP = false; _processSetStaticSubnetMask.start(script, QStringList() << iface() << vSubnetMask); } /*! * \brief WifiInterface::onProcessFinishedSetSubnetMask * Called when the process to set the subnet mask finishes * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedSetSubnetMask(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError(tr("Failed to set subnet mask.")); return; } emit didSetSubnetMask(); } /*! * \brief WifiInterface::doRequestSetDNS * Issues a command to set the DNS * \param vDNS - (QString) the DNS */ void WifiInterface::doRequestSetDNS(const QString &vDNS) { LOG_DEBUG(QString("Handling request to set DNS: %1").arg(vDNS)); if (_processSetDNS.state() != QProcess::NotRunning) { LOG_DEBUG(QString("Rejecting request for %1. %2 is already running.") .arg(__FUNCTION__) .arg(_processSetDNS.objectName())); return; } QString script; if ( ! checkScript(script, Wifi_Set_DNS ) ) return; _processSetDNS.start(script, QStringList() << vDNS); } /*! * \brief WifiInterface::onProcessFinishedSetDNS * Called when the process that finishes setting the DNS completes * \param vExitCode - (int) the exit code * \param vExitStatus - (QProcess::ExitStatus) the exit status */ void WifiInterface::onProcessFinishedSetDNS(int vExitCode, QProcess::ExitStatus vExitStatus) { Q_UNUSED(vExitStatus) if (vExitCode != 0) { emit didError(tr("Failed to set DNS.")); return; } emit didSetDNS(); } /*! * \brief WifiInterface::securityTypesToStringList * Converts a QList of network security types to a QStringList * \param securityTypes (QList) the list of security type * \return (QStringList) the security types as a string list */ QStringList WifiInterface::securityTypesToStringList(const QList &securityTypes) { QStringList securityTypesStrList; for (const MWifiNetwork::SECURITY_TYPE &type : securityTypes) { securityTypesStrList.append(QString("%1").arg(type)); } return securityTypesStrList; } /*! * \brief variantListToSecurityTypes * Converts a QVariantList of security types to a QList * \param securityTypesVar (QVariantList) security types * \return (QList) the list of network security types */ QList WifiInterface::variantListToSecurityTypes(const QList &securityTypesVar) { QList securityTypes; for (const QVariant &type : securityTypesVar) { bool ok = false; MWifiNetwork::SECURITY_TYPE val = MWifiNetwork::SECURITY_TYPE(type.toInt(&ok)); if (ok) securityTypes.append(val); } return securityTypes; } /*! * \brief WifiInterface::checkScript * \details Prepends the script folder path to the script name and checks if the script exists and is executable. * \param vScript : The script name with full path which will be set in this parameter passed argument. * \param vShellScript : The shell script name * \return true if succeeds and false otherwise */ bool WifiInterface::checkScript(QString &vScript, const QString &vShellScript) { vScript = Storage::Scripts_Path_Name() + vShellScript; QFileInfo info(vScript); if ( ! info.exists () ) { LOG_DEBUG(QString("script %1 does not exist." ).arg(vScript)); return false; } if ( ! info.isExecutable() ) { LOG_DEBUG(QString("script %1 is not executable." ).arg(vScript)); return false; } return true; }