/*! * * Copyright (c) 2021-2024 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 DeviceView.cpp * \author (last) Behrouz NematiPour * \date (last) 11-Sep-2023 * \author (original) Behrouz NematiPour * \date (original) 03-Jun-2021 * */ #include "DeviceView.h" // Qt // Project #include "ApplicationController.h" #include "GuiController.h" #include "DeviceController.h" #include "GuiGlobals.h" #include "encryption.h" #include "MWifiNetwork.h" VIEW_DEF_CLASS_EX(VDevice, QAbstractListModel) void VDevice::initConnections() { DEVICE_VIEW_INIT_CONNECTIONS_LIST connect(&_DeviceController , SIGNAL(didPOSTOSVersionData(QString)), this , SLOT( onPOSTOSVersionData(QString))); } // ================================================================================================== // ================================================= developer implementation section // ================================================================================================== // ================================================= OS Version void VDevice::onPOSTOSVersionData(const QString &vOSVersion) { osVersion(vOSVersion); } // ================================================= Brightness void VDevice::doInitBrightness() { // DEBUG : qDebug() << "HERE Request" << vValue; DeviceBrightnessRequestData data; data.mRead = true; emit didAttributeRequest(data); } void VDevice::brightnessRequest(const quint8 &vValue) { // DEBUG : qDebug() << "HERE Request" << vValue; DeviceBrightnessRequestData data; data.mBrightnessPercent = vValue; emit didAttributeRequest(data); } void VDevice::onAttributeResponse(const DeviceBrightnessResponseData &vData) { // DEBUG : qDebug() << "HERE Response" << vData.mBrightnessPercent; if ( vData.mAccepted ) { brightness(vData.mBrightnessPercent); status(""); } else { // this has to be called to let Gui to set to old value that device controller provided. emit brightnessChanged(vData.mBrightnessPercent); status(vData.mMessage); } accepted(vData.mAccepted); reason (vData.mReason ); // has to be the last one response(true); } // ================================================= Crypt Setup void VDevice::doInitCryptSetup() { // Nothing for now. } void VDevice::cryptSetupRequest(const QString &vCommand) { // DEBUG : qDebug() << "HERE Request" << vValue; cryptSetupEnabled(false); DeviceCryptSetupRequestData data; data.mCommand = vCommand; bool ok = false; data.mPassword = encryption::configurationsPassword( ok ); if ( ! ok ) { // not enough infromation to create a secure passowrd status(tr("Not enough secure information provided")); } else { emit didAttributeRequest(data); } } void VDevice::onAttributeResponse(const DeviceCryptSetupResponseData &vData) { // this has to be called to let Gui to set to old value that device controller provided. // this response is not updating the cryptsetup attribute. // cryptsetup attribute will containe the command to be sent to the cryptsetup script // and the retrurned message can be the model message in vData.mMessage status(vData.mMessage); accepted(vData.mAccepted); reason (vData.mReason ); // Only set to enable if request failed with a reason reported, disable otherwise //DEBUG qDebug()<< "accepted " << vData.mAccepted << " reason "<< vData.mReason; cryptSetupEnabled (!vData.mAccepted && vData.mReason != 0); // has to be the last one response(true); } // ================================================= Bluetooth Paired Reset void VDevice::doInitBluetoothPairedReset() { // DEBUG : qDebug() << "HERE Init"; DeviceBluetoothPairedResetRequestData data; emit didAttributeRequest(data); } void VDevice::bluetoothPairedResetRequest(const quint8 &) { // DEBUG : qDebug() << "HERE Request"; // Nothing to be done here. This property will not be assigned. } void VDevice::onAttributeResponse(const DeviceBluetoothPairedResetResponseData &vData) { // DEBUG : qDebug() << "HERE Response" << vData.mAccepted << vData.mReason << vData.mMessage; // this has to be called to let Gui to set to old value that device controller provided. status(vData.mMessage); accepted(vData.mAccepted); reason (vData.mReason ); // has to be the last one emit bluetoothPairedResetChanged(vData.mReason); response(true); } // ================================================= Bluetooth Paired Query void VDevice::doInitBluetoothPairedQuery() { // DEBUG : qDebug() << "HERE Init"; DeviceBluetoothPairedQueryRequestData data; emit didAttributeRequest(data); } void VDevice::bluetoothPairedQueryRequest(const QStringList &) { // DEBUG : qDebug() << "HERE Request"; // Nothing to be done here. This property will not be assigned. } void VDevice::onAttributeResponse(const DeviceBluetoothPairedQueryResponseData &vData) { // DEBUG : qDebug() << "HERE Response" << vData.mAccepted << vData.mReason << vData.mMessage; // this has to be called to let Gui to set to old value that device controller provided. status(vData.mMessage); accepted(vData.mAccepted); reason (vData.mReason ); // has to be the last one emit bluetoothPairedQueryChanged(vData.mInfo); response(true); } // ================================================= RootSSHAccess void VDevice::doInitRootSSHAccess() { // DEBUG : qDebug() << "HERE Request" << vValue; DeviceRootSSHAccessRequestData data; data.mIsGet = true; emit didAttributeRequest(data); } void VDevice::rootSSHAccessRequest(const Qt::CheckState &vValue) { // DEBUG : qDebug() << "HERE Request" << vValue; DeviceRootSSHAccessRequestData data; data.mIsGet = false; data.mRootSSHAccess = vValue; emit didAttributeRequest(data); } void VDevice::onAttributeResponse(const DeviceRootSSHAccessResponseData &vData) { if ( vData.mAccepted ) { rootSSHAccess(vData.mRootSSHAccess); status(""); } else { // this has to be called to let Gui to set to old value that device controller provided. emit rootSSHAccessChanged(vData.mRootSSHAccess); status(vData.mMessage); } accepted(vData.mAccepted); reason (vData.mReason ); // has to be the last one response(true); } // ================================================= Factory Reset void VDevice::doInitFactoryReset() { // Nothing for now. } void VDevice::factoryResetRequest(const QString &vCommand) { Q_UNUSED(vCommand) // DEBUG : qDebug() << "HERE Request" << vCommand; factoryResetEnabled(false); DeviceFactoryResetRequestData data; emit didAttributeRequest(data); } void VDevice::onAttributeResponse(const DeviceFactoryResetResponseData &vData) { // QDEBUG : qDebug() << "HERE Response " << Q_FUNC_INFO << " accepted: " << vData.mAccepted; // this has to be called to let Gui to set to old value that device controller provided. status(vData.mMessage); accepted(vData.mAccepted); reason (vData.mReason ); factoryResetEnabled(isCompleteResponse(vData)); // has to be the last one response(true); } // ================================================= Decommission void VDevice::doInitDecommission() { // Nothing for now. } void VDevice::decommissionRequest(const QString &vCommand) { Q_UNUSED(vCommand) // DEBUG : qDebug() << "HERE Request" << vCommand; decommissionEnabled(true); DeviceDecommissionRequestData data; bool ok = false; data.mPassword = encryption::configurationsPassword( ok ); if ( ! ok ) { // not enough infromation to create a secure passowrd status(tr("Not enough secure information provided")); } else { emit didAttributeRequest(data); } emit didAttributeRequest(data); } void VDevice::onAttributeResponse(const DeviceDecommissionResponseData &vData) { //QDEBUG : qDebug() << "HERE Response " << Q_FUNC_INFO << " accepted: "<< vData.mAccepted << vData.mReason; // this has to be called to let Gui to set to old value that device controller provided. status(vData.mMessage); accepted(vData.mAccepted); reason (vData.mReason ); decommissionEnabled(isCompleteResponse(vData)); // has to be the last one response(true); } // ================================================= WifiList void VDevice::doInitWifiList() { wifiListRequest({}); } void VDevice::wifiListRequest(const QStringList &) { QString norification = QObject::tr("The Wifi list scan started."); status( norification ); wifiListEnabled(false); DeviceWifiListRequestData data; emit didAttributeRequest(data); } void VDevice::onAttributeResponse(const DeviceWifiListResponseData &vData) { // DEBUG : qDebug() << " 2 ---------- " << __FUNCTION__ << vData.mMessage << result << vData.mCompleted; if ( vData.mCompleted ) { dataClear(); if ( vData.mAccepted ) { wifiListEnabled(true); parseWifiListResult(vData.mWifiList); } else { wifiList({}); } status(vData.mMessage); } accepted(vData.mAccepted); reason (vData.mReason ); // has to be the last one response(true); } /*! * \brief Network::parseWifiListResult * \details Extract desired information from the WiFi scan output. Sorts by signal stength * \param vResult - (QString) output collected from QProcess execution * \return List of the Found SSIDs in a model. */ void View::VDevice::parseWifiListResult(const QString &vResult) { enum SSIDInfo_Enum { eSSID , eBSSID , eFREQ , eRATE , eSIGNAL , eSECURITY , eWPA_FLAGS , eRSN_FLAGS , eIN_USE , }; enum ValueUnit_Enum { eValue , eUnit , eCount , }; struct SSIDInfo { QString mSSID ; QString mBSSID ; QString mFREQ_Max ; QString mRATE_Max ; quint16 mSIGNAL_Max ; QString mSECURITY ; QString mFLAGS ; // eWPA_FLAGS, eRSN_FLAGS are exclusive bool mInUse = false ; bool mSupported = true ; QString toString() { QStringList fields = QStringList() << mSSID << mBSSID << mFREQ_Max << mRATE_Max << QString::number(mSIGNAL_Max) << mSECURITY << mFLAGS << (mSupported ? "T" : "") << (mInUse ? "T" : ""); return fields.join(','); } }; QString mResult = vResult; SSIDInfo ssidInfo; QHash ssidInfoList; // the Freq, Rate units QString mSSID; const QString mFREQ_Unit = " MHz"; const QString mRATE_Unit = " Mbit/s"; quint32 mFREQ_Value = 0; quint32 mRATE_Value = 0; // Removing the units once from the result to accelerate parsing. (will be added when done) mResult.remove(mFREQ_Unit); mResult.remove(mRATE_Unit); QStringList lines = mResult.split('\n'); for ( int row = 0; row < lines.count(); row++ ) { QStringList fields = lines[row].split(','); qDebug() << fields.join("-"); if ( fields[eSSID].trimmed().isEmpty() ) continue; // hidden networks, or an incorrect entry QString mWPA_FLAGS; QString mRSN_FLAGS; for ( int index = 0; index < fields.count(); index++ ) { // the list has to be sorted and the script is written that way. QString field = fields[index].trimmed(); if ( row ) { // if is not first row if ( mSSID == fields[eSSID] ) { // if is the same SSID just update necessary fields quint32 value = 0; switch (index) { case eFREQ : value = QString("%1").arg(field).toInt(); if ( mFREQ_Value < value ) { mFREQ_Value = value; } break; case eRATE : value = QString("%1").arg(field).toInt(); if ( mRATE_Value < value ) { mRATE_Value = value; } break; case eSIGNAL : value = QString("%1").arg(field).toInt(); if ( ssidInfo.mSIGNAL_Max < value ) { ssidInfo.mSIGNAL_Max = value; } break; case eIN_USE : value = field.contains("*"); ssidInfo.mInUse = value; break; default: break; } } else { // else add the previous one and continue to the next. if ( ! mSSID.trimmed().isEmpty() ) { ssidInfo.mSSID = mSSID; ssidInfo.mFREQ_Max += QString::number(mFREQ_Value) + mFREQ_Unit; ssidInfo.mRATE_Max += QString::number(mRATE_Value) + mRATE_Unit; ssidInfoList[mSSID] = ssidInfo; //DEBUG qDebug() << ssidInfo.toString(); } // clean up / reset ssidInfo.mFREQ_Max = ""; ssidInfo.mRATE_Max = ""; ssidInfo.mFLAGS = ""; } } switch (index) { // DO NOT USE default in this switch case eSSID : mSSID = field; break; case eBSSID : /*data.mBSSID = field;*/ break; // not directly used for now case eFREQ : mFREQ_Value = QString("%1").arg(field).toInt(); break; case eRATE : mRATE_Value = QString("%1").arg(field).toInt(); break; case eSIGNAL : ssidInfo.mSIGNAL_Max = QString("%1").arg(field).toInt(); break; case eIN_USE : ssidInfo.mInUse = field.contains("*"); break; case eSECURITY : ssidInfo.mSECURITY = field; if ( field.isEmpty() ) { ssidInfo.mSupported = false; } else { ssidInfo.mSupported = field.remove(QRegExp("(WPA[23])")).trimmed().isEmpty(); } break; case eWPA_FLAGS : if ( field.contains("tkip") ) { mWPA_FLAGS += " TKIP" ; ssidInfo.mSupported = false; } if ( field.contains("ccmp") ) { mWPA_FLAGS += " AES" ; } if ( ! mWPA_FLAGS.isEmpty() ) { ssidInfo.mFLAGS = mWPA_FLAGS.trimmed(); } break; case eRSN_FLAGS : if ( field.contains("tkip") ) { mRSN_FLAGS += " TKIP" ; ssidInfo.mSupported = false; } if ( field.contains("ccmp") ) { mRSN_FLAGS += " AES" ; } if ( field.contains("sae" ) ) { mRSN_FLAGS += " SAE" ; } if ( ! mRSN_FLAGS.isEmpty() ) { ssidInfo.mFLAGS = mRSN_FLAGS.trimmed(); } break; } } } for (const auto &ssid: qAsConst(ssidInfoList)) { DataModel data; data.mWifiMacAddress = ssid.mBSSID; data.mWifiSSID = ssid.mSSID; data.mWifiSecurityTypes = ssid.mSECURITY; data.mWifiSignalLevel = ssid.mSIGNAL_Max; data.mWifiSupported = ssid.mSupported; data.mWifiConnected = ssid.mInUse ; dataAppend( data, ssid.mInUse); } } void View::VDevice::dataAppend(const DataModel &vData, bool vFirst) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); if ( vFirst ) { _dataList.insert(0, vData); } else { _dataList.append( vData); } endInsertRows(); } void View::VDevice::dataClear() { beginRemoveRows(QModelIndex(), 0, rowCount()); _dataList.clear(); endRemoveRows(); } QVariant View::VDevice::data(const QModelIndex &vIndex, int vRole) const { if (! vIndex.isValid() || vIndex.row() >= _dataList.count()) return QVariant(); DataModel dataList = _dataList[vIndex.row()]; switch (vRole) { // ----- WiFi case eRole_WifiMacAddress : return dataList.mWifiMacAddress ; case eRole_WifiSsid : return dataList.mWifiSSID ; case eRole_WifiSecurityTypes : return dataList.mWifiSecurityTypes ; case eRole_WifiSignalLevel : return dataList.mWifiSignalLevel ; case eRole_WifiSupported : return dataList.mWifiSupported ; case eRole_WifiConnected : return dataList.mWifiConnected ; // ----- Bluetooth case eRole_BLE_UNUSED : return ""; ; } return QString("Wifi %1").arg(vIndex.row()); }