Index: denali.pro.user =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- denali.pro.user (.../denali.pro.user) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ denali.pro.user (.../denali.pro.user) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -1,6 +1,6 @@ - + EnvironmentId Index: denali.qrc =================================================================== diff -u -r5600d2133dd0ea6dc1f733aa78bd26e2a4892a38 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- denali.qrc (.../denali.qrc) (revision 5600d2133dd0ea6dc1f733aa78bd26e2a4892a38) +++ denali.qrc (.../denali.qrc) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -15,6 +15,7 @@ sources/gui/qml/dialogs/Alert.qml sources/gui/qml/dialogs/VitalsEntry.qml sources/gui/qml/dialogs/JoinNetwork.qml + sources/gui/qml/dialogs/DisconnectNetwork.qml resources/images/Settings_gear_setting_tools-128.png Index: scripts/wifi_disconnect_network.sh =================================================================== diff -u --- scripts/wifi_disconnect_network.sh (revision 0) +++ scripts/wifi_disconnect_network.sh (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -0,0 +1,5 @@ +#!/bin/sh +iface=$1 +killall wpa_supplicant +rm -f /etc/wpa_supplicant +./wifi_reset_interface.sh $iface Index: sources/gui/qml/dialogs/DisconnectNetwork.qml =================================================================== diff -u --- sources/gui/qml/dialogs/DisconnectNetwork.qml (revision 0) +++ sources/gui/qml/dialogs/DisconnectNetwork.qml (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -0,0 +1,73 @@ +/*! + * + * Copyright (c) 2019-2020 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 Alert.qml + * \author (last) Peter Lucia + * \date (last) 30-Nov-2020 + * \author (original) Peter Lucia + * \date (original) 30-Nov-2019 + * + */ + +// Qt +import QtQuick 2.12 + +// Project +// Qml imports +import "qrc:/globals" +import "qrc:/components" + +/*! + * \brief Contains the Vitals Entry Implementation + */ +ModalDialog { id: _root + property string ssid : "" + property string macAddress : "" + objectName: "DisconnectNetwork" // SquishQt testability + contentItem.objectName: "DisconnectNetworkContent" + modal: false + + Item { id: _titleBar + height: _root.height / 4 + width: _root.width + + Text { id: _titleBarText + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + text: qsTr("Disconnect from " + ssid) + anchors.centerIn: _titleBar + } + } + + Row { id: _buttons + spacing: Variables.buttonSpacing + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: Variables.dialogMargin / 2 + } + + TouchRect { id: _confirm + objectName: "_disconnectNetworkConfirm" + width: _root.width / 3 + text.text: qsTr("CONFIRM") + button.onPressed: { + vNetworkModel.doDisconnectNetwork(macAddress) + close() + } + } + + TouchRect { id: _cancel + objectName: "_disconnectNetworkCancel" + width: _root.width / 3 + text.text: qsTr("CANCEL") + button.onPressed: { + close() + } + } + } +} Index: sources/gui/qml/pages/SettingsWifi.qml =================================================================== diff -u -r1bfd7fcf476b6cc1ad7fce69e8970bc55ec1a621 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/gui/qml/pages/SettingsWifi.qml (.../SettingsWifi.qml) (revision 1bfd7fcf476b6cc1ad7fce69e8970bc55ec1a621) +++ sources/gui/qml/pages/SettingsWifi.qml (.../SettingsWifi.qml) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -32,6 +32,13 @@ signal clickedBack() + onVisibleChanged: { + if (visible) { + vNetworkModel.doRequestIPSettings() + vNetworkModel.doScan() + } + } + BackButton { id : _backButton onClicked: { _root.clickedBack() @@ -71,7 +78,6 @@ label.width: Variables.settingsWIFIInputWidth anchors { top: parent.top - topMargin: Variables.settingsWIFIMargin left: parent.left } validator: ipValidator @@ -176,7 +182,7 @@ } } - ListView { id: _pairedDevices + ListView { id: _networkList model: vNetworkModel anchors { top: parent.top Index: sources/storage/StorageGlobals.cpp =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/storage/StorageGlobals.cpp (.../StorageGlobals.cpp) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ sources/storage/StorageGlobals.cpp (.../StorageGlobals.cpp) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -55,6 +55,7 @@ #elif BUILD_FOR_TARGET const char *Wifi_Scripts_Dir = "/home/root/"; #endif + const char *Wifi_Disconnect_Network = "wifi_disconnect_network.sh"; const char *Wifi_Generate_WPA_Supplicant = "wifi_generate_wpa_supplicant.sh"; const char *Wifi_Read_DNS = "wifi_read_dns.sh"; const char *Wifi_Read_Gateway = "wifi_read_gateway.sh"; Index: sources/storage/StorageGlobals.h =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/storage/StorageGlobals.h (.../StorageGlobals.h) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ sources/storage/StorageGlobals.h (.../StorageGlobals.h) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -41,6 +41,7 @@ // Wifi extern const char *Wifi_Scripts_Dir; + extern const char *Wifi_Disconnect_Network; extern const char *Wifi_Generate_WPA_Supplicant; extern const char *Wifi_Read_DNS; extern const char *Wifi_Read_Gateway; Index: sources/view/VNetworkModel.cpp =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/view/VNetworkModel.cpp (.../VNetworkModel.cpp) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ sources/view/VNetworkModel.cpp (.../VNetworkModel.cpp) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -16,22 +16,32 @@ { // incoming connect(&_WifiInterface, SIGNAL(didAddNetwork(const Network)), - this, SLOT(doAddNetwork(const Network))); + this, SLOT(doAddNetwork(const Network)), Qt::QueuedConnection); connect(&_WifiInterface, SIGNAL(didScanStatusChanged(const bool)), - this, SLOT(onScanStatusChanged(const bool))); + this, SLOT(onScanStatusChanged(const bool)), Qt::QueuedConnection); connect(&_WifiInterface, SIGNAL(didConnectToNetwork(const Network)), - this, SLOT(onConnectedToNetwork(const Network))); + this, SLOT(onConnectedToNetwork(const Network)), Qt::QueuedConnection); + connect(&_WifiInterface, SIGNAL(didDisconnectNetwork(Network)), + this, SLOT(onDisconnectedNetwork(const Network)), Qt::QueuedConnection); + + connect(&_WifiInterface, SIGNAL(didError(const QString)), + this, SLOT(onError(const QString)), Qt::QueuedConnection); + // outgoing connect(this, SIGNAL(didScan()), &_WifiInterface, SLOT(doScan())); - // outgoing connect(this, SIGNAL(didJoinNetwork(const Network, const QString)), &_WifiInterface, SLOT(doJoinNetwork(const Network, const QString))); + connect(this, SIGNAL(didDisconnectNetwork(Network)), + &_WifiInterface, SLOT(doDisconnectNetwork(const Network))); + + connect(this, SIGNAL(didRequestIPSettings()), + &_WifiInterface, SLOT(doRequestIPSettings())); } /*! @@ -181,6 +191,24 @@ } /*! + * \brief VNetworkModel::doDisconnectNetwork + * Handles request from qml to disconnect from a network + * \param vMacAddress - (QString) the mac address of the network to disconnect from + */ +void VNetworkModel::doDisconnectNetwork(const QString &vMacAddress) +{ + for (const Network &network : _networks) + { + if (network.macAddress() == vMacAddress) + { + status(tr("Disconnecting from %1...").arg(network.ssid())); + emit didDisconnectNetwork(network); + return; + } + } +} + +/*! * \brief VNetworkModel::onConnectedToNetwork * Called when we have connected to a network. * \param vNetwork - (Network) the network we have connected to @@ -194,3 +222,33 @@ dns(vNetwork.ipSettings().mDns); status(tr("Connected to %1.").arg(vNetwork.ssid())); } + +/*! + * \brief VNetworkModel::onDisconnectedNetwork + * Called when we have disconnected from a network. + * \param vNetwork - (Network) the network we have disconnected from + */ +void VNetworkModel::onDisconnectedNetwork(const Network &vNetwork) +{ + LOG_DEBUG(QString("Disconnected from %1.").arg(vNetwork.ssid())); + status(tr("Disconnected from %1.").arg(vNetwork.ssid())); +} + +/*! + * \brief VNetworkModel::doRequestIPSettings + * Called when QML requests the IP settings + */ +void VNetworkModel::doRequestIPSettings() +{ + emit didRequestIPSettings(); +} + +/*! + * \brief VNetworkModel::onError + * Called when the wifi interface emits an error + * \param vMessage - (QString) the error message + */ +void VNetworkModel::onError(const QString &vMessage) +{ + status(vMessage); +} Index: sources/view/VNetworkModel.h =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/view/VNetworkModel.h (.../VNetworkModel.h) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ sources/view/VNetworkModel.h (.../VNetworkModel.h) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -52,12 +52,16 @@ signals: void didScan(); void didJoinNetwork(const Network, const QString); + void didDisconnectNetwork(const Network); + void didRequestIPSettings(); public slots: void doScan(); void doAddNetwork(const Network &vNetwork); bool doCheckIfConnected(const QString &vMacAddress); void doJoinNetwork(const QString &vMacAddress, const QString &vPassword); + void doDisconnectNetwork(const QString &vMacAddress); + void doRequestIPSettings(); protected: QHash roleNames() const; @@ -69,6 +73,8 @@ private slots: void onScanStatusChanged(const bool &vScanning); void onConnectedToNetwork(const Network &vNetwork); + void onDisconnectedNetwork(const Network &vNetwork); + void onError(const QString &vMessage); }; } Index: sources/wifi/WifiInterface.cpp =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/wifi/WifiInterface.cpp (.../WifiInterface.cpp) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ sources/wifi/WifiInterface.cpp (.../WifiInterface.cpp) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -3,6 +3,7 @@ // Qt #include #include +#include // Project #include "main.h" @@ -17,10 +18,8 @@ void WifiInterface::onInitConnections() { - connect(&_processScan, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(onScanFinished(int, QProcess::ExitStatus))); - connect(this, SIGNAL(didFailToConnect(const QString)), + connect(this, SIGNAL(didError(const QString)), this, SLOT(onLogFailure(const QString))); } @@ -83,40 +82,31 @@ */ void WifiInterface::doScan() { + QtConcurrent::run([=]() { + if (_scanRunning) + { + LOG_DEBUG("Wifi network scan is already running."); + return; + } + LOG_DEBUG("Scanning for Wifi Access Points..."); + QProcess process; + process.setWorkingDirectory(Wifi_Scripts_Dir); + _scanRunning = true; + emit didScanStatusChanged(_scanRunning); + process.start(Wifi_Scan_For_Networks); + process.waitForFinished(_scanTimeout); + QString out = process.readAllStandardOutput(); + QString err = process.readAllStandardError(); + LOG_DEBUG(out); + LOG_DEBUG(err); + _scanRunning = false; + emit didScanStatusChanged(_scanRunning); + onParseWifiScan(out); + }); - if (_scanRunning) - { - LOG_DEBUG("Wifi network scan is already running."); - return; - } - - LOG_DEBUG("Scanning for Wifi Access Points..."); - _processScan.setWorkingDirectory(Wifi_Scripts_Dir); - _scanRunning = true; - emit didScanStatusChanged(_scanRunning); - _processScan.start(Wifi_Scan_For_Networks); - } /*! - * \brief WifiInterface::onScanFinished - * Called when finished scanning for networks (success or error) - * \param vPid - pid of the scan for networks process - * \param vExitStatus - the status upon exit - */ -void WifiInterface::onScanFinished(int vPid, QProcess::ExitStatus vExitStatus) -{ - LOG_DEBUG(QString("%1: %2,%3").arg(__FUNCTION__).arg(vPid).arg(vExitStatus)); - QString out = _processScan.readAllStandardOutput(); - QString err = _processScan.readAllStandardError(); - LOG_DEBUG(out); - LOG_DEBUG(err); - _scanRunning = false; - emit didScanStatusChanged(_scanRunning); - onParseWifiScan(out); -} - -/*! * \brief Network::onParseWifiScan * Extract desired information from the wifi scan output. Sorts by signal stength * @@ -178,39 +168,81 @@ */ void WifiInterface::doJoinNetwork(const Network &vNetwork, const QString &vPassword) { - LOG_DEBUG(QString("Joining Network %1").arg(vNetwork.ssid())); - _network = vNetwork; - if (!generateWPASupplicant(_network, vPassword)) - { - emit didFailToConnect("Could not configure network."); - return; - } + QtConcurrent::run([=]() { + LOG_DEBUG(QString("Joining Network %1").arg(vNetwork.ssid())); + if (!generateWPASupplicant(vNetwork, vPassword)) + { + emit didError("Could not configure network."); + return; + } - if (!startWPASupplicant()) - { - emit didFailToConnect("Could not configure network."); - return; - } + if (!startWPASupplicant()) + { + emit didError("Could not configure network."); + return; + } - // TODO: Add option to setup with static IP settings instead - if (!requestAutoAssignedIP()) - { - emit didFailToConnect("Could not obtain IP Address."); - return; - } + // TODO: Add option to setup with static IP settings instead + if (!requestAutoAssignedIP()) + { + emit didError(QString("Could not connect to %1").arg(vNetwork.ssid())); + return; + } + Network network = vNetwork; + network.ipSettings(getIPSettings()); + emit didConnectToNetwork(network); + }); +} + +/*! + * \brief WifiInterface::getIPSettings + * Gets the IP settings from the device. If an IP address + * is not found, all other IP settings are left blank as well. + */ +Network::IPSettings WifiInterface::getIPSettings() +{ Network::IPSettings ipSettings; QString output = readIPSettings(); ipSettings.mIPAddress = parseIP(output); + if (ipSettings.mIPAddress == "") { + return ipSettings; + } ipSettings.mBroadcast = parseBroadcast(output); ipSettings.mSubnetMask = parseSubnetMask(output); ipSettings.mGateway = readGateway(); ipSettings.mDns = readDNS(); - _network.ipSettings(ipSettings); - emit didConnectToNetwork(_network); + return ipSettings; } /*! + * \brief WifiInterface::doRequestIPSettings + * Handles a request to read the IP settings of the device. + */ +void WifiInterface::doRequestIPSettings() +{ + emit didGetIPSettings(getIPSettings()); +} + +/*! + * \brief WifiInterface::doDisconnectNetwork + * Disconnects from the specified network + * \param vNetwork - (Network) the network to disconnect from + */ +void WifiInterface::doDisconnectNetwork(const Network &vNetwork) +{ + LOG_DEBUG(QString("Disconnecting from Network %1").arg(vNetwork.ssid())); + QProcess process; + process.start(Wifi_Disconnect_Network, + QStringList() << _iface); + if (process.waitForFinished(_defaultTimeout)) + emit didDisconnectNetwork(vNetwork); + process.kill(); + emit didError(tr("Failed to disconnect from %1").arg(vNetwork.ssid())); +} + + +/*! * \brief WifiInterface::generateWPASupplicant * Generates the WPA Supplicant configuration file * \param vNetwork (Network) the network w/ ssid we want to connect to @@ -220,11 +252,17 @@ bool WifiInterface::generateWPASupplicant(const Network &vNetwork, const QString &vPassword) { LOG_DEBUG("Generating WPA Supplicant..."); - _processJoinNetwork.start(Wifi_Generate_WPA_Supplicant, + QProcess process; + process.start(Wifi_Generate_WPA_Supplicant, QStringList() << vNetwork.ssid() << vPassword << _wpaSupplicantConfPath); - return _processJoinNetwork.waitForFinished(_defaultTimeout); + if (!process.waitForFinished(_defaultTimeout)) + { + process.kill(); + return false; + } + return true; } /*! @@ -235,23 +273,36 @@ bool WifiInterface::startWPASupplicant() { LOG_DEBUG("Starting wpa supplicant..."); - _processJoinNetwork.start(Wifi_Start_WPA_Supplicant, + QProcess process; + process.start(Wifi_Start_WPA_Supplicant, QStringList() << _iface << _wpaSupplicantConfPath); - return _processJoinNetwork.waitForFinished(_defaultTimeout); + if (!process.waitForFinished(_defaultTimeout)) + { + process.kill(); + return false; + } + return true; } /*! * \brief WifiInterface::requestAutoAssignedIP * Requests an auto-assigned IP addressed * \return true if successful, false on timeout */ -bool WifiInterface::requestAutoAssignedIP() +bool WifiInterface::requestAutoAssignedIP(int vTries) { - LOG_DEBUG("Requesting auto-assigned IP address..."); - _processJoinNetwork.start(Wifi_Get_Auto_Assigned_IP, + LOG_DEBUG(QString("Requesting auto-assigned IP address...")); + QProcess process; + process.start(Wifi_Get_Auto_Assigned_IP, QStringList() << _iface); - return _processJoinNetwork.waitForFinished(_dhcpTimeout); + if (!process.waitForFinished(_dhcpTimeout)) + { + if (vTries > 0) + return requestAutoAssignedIP(--vTries); + return false; + } + return true; } /*! @@ -262,10 +313,13 @@ QString WifiInterface::readIPSettings() { QString result = ""; - _processGetIPAddress.start(Wifi_Read_IP_Settings, + QProcess process; + process.start(Wifi_Read_IP_Settings, QStringList() << _iface); - if (_processGetIPAddress.waitForFinished(_defaultTimeout)) - result = _processGetIPAddress.readAllStandardOutput(); + if (process.waitForFinished(_defaultTimeout)) + result = process.readAllStandardOutput(); + else + process.kill(); LOG_DEBUG(QString("Output with IP address information: %1").arg(result)); return result; } @@ -342,9 +396,11 @@ */ QString WifiInterface::readGateway() { - _processGetIPAddress.start(Wifi_Read_Gateway); - if (_processGetIPAddress.waitForFinished(_defaultTimeout)) - return parseGateway(_processGetIPAddress.readAllStandardOutput()); + QProcess process; + process.start(Wifi_Read_Gateway); + if (process.waitForFinished(_defaultTimeout)) + return parseGateway(process.readAllStandardOutput()); + process.kill(); return ""; } @@ -355,8 +411,10 @@ */ QString WifiInterface::readDNS() { - _processGetIPAddress.start(Wifi_Read_DNS); - if (_processGetIPAddress.waitForFinished(_defaultTimeout)) - return parseDNS(_processGetIPAddress.readAllStandardOutput()); + QProcess process; + process.start(Wifi_Read_DNS); + if (process.waitForFinished(_defaultTimeout)) + return parseDNS(process.readAllStandardOutput()); + process.kill(); return ""; } Index: sources/wifi/WifiInterface.h =================================================================== diff -u -r2085962f7bd0a2239ee5c857928a11d5e38fe0a2 -rc77365fa76422bc2150e58d483c446325b50f4b8 --- sources/wifi/WifiInterface.h (.../WifiInterface.h) (revision 2085962f7bd0a2239ee5c857928a11d5e38fe0a2) +++ sources/wifi/WifiInterface.h (.../WifiInterface.h) (revision c77365fa76422bc2150e58d483c446325b50f4b8) @@ -27,11 +27,8 @@ bool _init = false; bool _scanRunning = false; int _defaultTimeout = 5000; - int _dhcpTimeout = 10000; - QProcess _processScan; - QProcess _processJoinNetwork; - QProcess _processGetIPAddress; - Network _network; + int _dhcpTimeout = 10000; + int _scanTimeout = 30000; const QString _iface = "wlan0"; const QString _wpaSupplicantConfPath = "/etc/wpa_supplicant.conf"; @@ -43,7 +40,8 @@ private: bool generateWPASupplicant(const Network &vNetwork, const QString &vPassword); bool startWPASupplicant(); - bool requestAutoAssignedIP(); + bool requestAutoAssignedIP(int vTries = 4); + Network::IPSettings getIPSettings(); QString readIPSettings(); QString readGateway(); QString readDNS(); @@ -60,16 +58,19 @@ bool doInit(); void doScan(); void doJoinNetwork(const Network &vNetwork, const QString &vPassword); + void doDisconnectNetwork(const Network &vNetwork); + void doRequestIPSettings(); signals: void didAddNetwork(const Network); void didScanStatusChanged(const bool); void didConnectToNetwork(const Network); - void didFailToConnect(const QString); + void didDisconnectNetwork(const Network); + void didError(const QString); + void didGetIPSettings(const Network::IPSettings); private slots: void onQuit(); - void onScanFinished(int, QProcess::ExitStatus); void onParseWifiScan(const QString &vOutput); void onLogFailure(const QString &vMessage); };