Index: sources/device/DeviceController.cpp =================================================================== diff -u -rd0c1c6aa5856a7acbca29a4c5435cc20db3ea383 -r6c6f1f5d466badd9b4fd67be7c907234c342b2a2 --- sources/device/DeviceController.cpp (.../DeviceController.cpp) (revision d0c1c6aa5856a7acbca29a4c5435cc20db3ea383) +++ sources/device/DeviceController.cpp (.../DeviceController.cpp) (revision 6c6f1f5d466badd9b4fd67be7c907234c342b2a2) @@ -1,13 +1,13 @@ /*! * - * Copyright (c) 2021-2022 Diality Inc. - All Rights Reserved. + * Copyright (c) 2021-2023 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 DeviceController.cpp - * \author (last) Behrouz NematiPour - * \date (last) 11-Nov-2021 + * \author (last) Vy + * \date (last) 10-Apr-2023 * \author (original) Behrouz NematiPour * \date (original) 03-Jun-2021 * @@ -24,11 +24,14 @@ #include // Project +#include "Threads.h" #include "StorageGlobals.h" #include "Logger.h" #include "ApplicationController.h" #include "FileHandler.h" #include "DeviceModels.h" +#include "Settings.h" +#include "encryption.h" // namespace using namespace Model; @@ -85,19 +88,9 @@ */ void DeviceController::quit() { - // coco begin validated: Application termination is not correctly done in coco!!! - // it has been tested and works perfectly fine in normal run. - quitThread(); // validated + quitThread(); } -// coco end -void DeviceController::onRemoveLogs(bool vInProgress) -{ - // coco begin validated: The log in progress requires user interaction - // it has been tested and works fine in normal run. - _pauseSpaceCheck = vInProgress; -} -// coco end /*! * \brief DeviceController::initConnections @@ -108,17 +101,27 @@ { connect(&_ApplicationController , SIGNAL(didUSBDriveUmount()), this , SLOT( onUSBDriveUmount())); - connect(&_Logger , SIGNAL(didRemoveLogs(bool)), - this , SLOT( onRemoveLogs(bool))); connect(this , SIGNAL(didScreenshot(const QImage &, const QString &)), this , SLOT( onScreenshot(const QImage &, const QString &))); connect(&_fileSystemWatcher , SIGNAL( fileChanged(const QString &)), this , SLOT( onWatchFileChanged(const QString &))); + connect(&_ApplicationController , SIGNAL(didPOSTEthernetData (const QString &)), + this , SLOT( onPOSTEthernetData (const QString &))); + connect(&_ApplicationController , SIGNAL(didPOSTWirelessData (const QString &)), + this , SLOT( onPOSTWirelessData (const QString &))); + connect(&_ApplicationController , SIGNAL(didPOSTBluetoothData (const QString &)), + this , SLOT( onPOSTBluetoothData (const QString &))); + connect(&_ApplicationController , SIGNAL(didPOSTCloudSyncData (const QString &)), + this , SLOT( onPOSTCloudSyncData (const QString &))); + DEVICE_DEV_INIT_CONNECTIONS_LIST + connect(this, SIGNAL(didEventThreadChange()), + this, SLOT( onEventThreadChange())); + } /*! @@ -137,6 +140,8 @@ connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); _thread->start(); moveToThread(_thread); + + emit didEventThreadChange( QPrivateSignal() ); } /*! @@ -146,15 +151,15 @@ */ void DeviceController::quitThread() { - // coco begin validated: Application termination is not correctly done in coco!!! + // 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()); // validated } -// coco end +// disabled coco end /*! * \brief DeviceController::usbSeek @@ -166,9 +171,9 @@ */ bool DeviceController::usbSeek(QString &vDevice) { - // coco begin validated: Needed User Interaction so tested manually + // disabled coco begin validated: Needed User Interaction so tested manually // This function cannot be tested on any device other than target - // because only on device the usb is /dev/sdX# and others are mmblk___ + // because only on device the usb is /dev/sdX# and others are mmcblk___ // but on VM and normal Linuxes all drives are /dev/sdX# and cannot be identified as USB. // And the difference between how USB is detected and sd-card is that // for the USB we need to look into /dev/sdX# @@ -185,7 +190,7 @@ } vDevice = device; return false; - // coco end + // disabled coco end } /*! @@ -199,19 +204,25 @@ */ bool DeviceController::driveSpaceCheck(const QString &vPath, qint64 &vTotalBytes, qint64 &vAvailableBytes, bool *vIsReadOnly) { - // coco begin validated: Needed User Interaction to make the device not ready so tested manually - bool isReadOnly; - if (! FileHandler::isMounted(vPath, &isReadOnly)) return false; - if (vIsReadOnly) *vIsReadOnly = isReadOnly; QStorageInfo storage(vPath); - bool isReady = storage.isReady(); - if (isReady) { + bool isReady = storage.isReady (); + bool isReadOnly = storage.isReadOnly(); + bool isMounted = FileHandler::isMounted(vPath); + + if ( vIsReadOnly ) *vIsReadOnly = isReadOnly; + + if ( isReady ) { vTotalBytes = storage.bytesTotal(); vAvailableBytes = storage.bytesAvailable(); } + + if ( ! isMounted || ! isReady ) { + isReady = false; + vTotalBytes = 0; + vAvailableBytes = 0; + } return isReady; } -// coco end /*! * \brief DeviceController::timerEvent @@ -233,73 +244,118 @@ */ void DeviceController::usbCheck() { - // coco begin validated: Needed User Interaction so tested manually QString device = ""; + usbSpaceCheck(); if (usbSeek(device)) { - if (! _umounted ) { + if (! _umounted ) { // avoid to mount the USB which has just been unmounted usbMount(device); - } else { + } else { // the umount is requested? usbUmount(USB_Mount_Point); } } else { if ( ! _removed ) { usbRemove(); } } - // coco end } /*! - * \brief DeviceController::sdcardFreeSpaceCheck - * \details Checks the drivers for available free space. + * \brief DeviceController::sdcardSpaceCheck + * \details Checks for the SD-Card drive space. */ void DeviceController::sdcardSpaceCheck() { - // coco begin validated: Needed User Interaction so tested manually + static bool mInitialized = false; + // Old Info ; // Current info + static bool mOIsReady = false; bool mCIsReady = false; + static bool mOIsReadOnly = false; bool mCIsReadOnly = false; + static qint64 mOAvailable = 0; qint64 mCAvailable = 0; + static quint8 mOPercent = 0; quint8 mCPercent = 0; - // Old Info ; // Current info - static bool mOIsReady ; bool mCIsReady ; - static bool mOIsReadOnly; bool mCIsReadOnly ; - static qint64 mOTotal ; qint64 mCTotal ; - static qint64 mOAvailable ; qint64 mCAvailable ; + qint64 mCTotal = 0; mCIsReady = driveSpaceCheck(Storage::SDCard_Base_Path_Name, mCTotal, mCAvailable, &mCIsReadOnly); - /// DEBUG: qDebug() << " ===== " << Storage::SDCard_Base_Path_Name << mCIsReady; - if (mOIsReadOnly != mCIsReadOnly || mOIsReady != mCIsReady) { + if (mOIsReadOnly != mCIsReadOnly || mOIsReady != mCIsReady || ! mInitialized ) { mOIsReadOnly = mCIsReadOnly; + mOIsReady = mCIsReady; + mInitialized = true; + //DEBUG:0: qDebug() << " ~~~~~~~~~~ " << __FUNCTION__ << mInitialized << mCIsReady << mOIsReady << mCIsReadOnly << mOIsReadOnly; emit didSDCardStateChange(mCIsReady, mCIsReadOnly); } - + //NOTE: this if block has to be independent of the mOIsReady != mCIsReady + // because current and old may be the same all the time and then this if block will not execute + // and reaches to the log and fills the log unnecessarily. if (! mCIsReady ) { - mOIsReady = mCIsReady; - mOTotal = 0; + mOPercent = 0; mOAvailable = 0; + emit didSDCardSpaceChange(mCIsReady, mCTotal, mCAvailable, mCPercent); return; } - quint8 mPercent = mCTotal ? ((100 * mCAvailable) / mCTotal) : 0; - if (mPercent < _minRequiredAvailableSpacePercent) { + mCPercent = mCTotal ? ((100 * mCAvailable) / mCTotal) : 0; + if (mCPercent < _minRequiredAvailableSpacePercent) { LOG_DEBUG(QString("SD-CARD space lower than %1%").arg(_minRequiredAvailableSpacePercent)); - emit didSDCardSpaceChange(mCIsReady, mCTotal, mCAvailable, mPercent); + emit didSDCardSpaceChange(mCIsReady, mCTotal, mCAvailable, mCPercent); emit didSDCardSpaceTooLow(_minRequiredAvailableSpacePercent); } /// DEBUG: qDebug() << Storage::SDCard_Base_Path_Name << mCIsReady << mOTotal << mCTotal << (mOTotal == mCTotal) << mOAvailable << mCAvailable << (mOAvailable == mCAvailable) << mPercent << mCIsReadOnly; + if (mOPercent != mCPercent && mOAvailable != mCAvailable ) { + mOPercent = mCPercent ; + mOAvailable = mCAvailable ; + emit didSDCardSpaceChange(mCIsReady, mCTotal, mCAvailable, mCPercent); + /// DEBUG: qDebug() << Storage::SDCard_Base_Path_Name << mCIsReady << mCTotal << mCAvailable << mPercent ; + } +} - if (mOTotal == mCTotal && - mOAvailable == mCAvailable) { - return; +/*! + * \brief DeviceController::usbSpaceCheck + * \details Checks for the USB drive space. + */ +void DeviceController::usbSpaceCheck() +{ + static bool mInitialized = false; + // Old Info ; // Current info + static bool mOIsReady = false; bool mCIsReady = false; + static bool mOIsReadOnly = false; bool mCIsReadOnly = false; + static qint64 mOTotal = 0; qint64 mCTotal = 0; + static qint64 mOAvailable = 0; qint64 mCAvailable = 0; + + quint8 mPercent = 0; + + mCIsReady = driveSpaceCheck(Storage::USB_Mount_Point, mCTotal, mCAvailable, &mCIsReadOnly); +#if BUILD_FOR_DESKTOP + mCIsReady = true; // it is set to always true since on desktop a local folder is used for the USB folder which doesn't need (un)mount. +#endif + if (mOIsReadOnly != mCIsReadOnly || mOIsReady != mCIsReady || ! mInitialized ) { + mOIsReadOnly = mCIsReadOnly; + mOIsReady = mCIsReady; + mInitialized = true; + emit didUSBStateChange(mCIsReady, mCIsReadOnly); + + if (! mCIsReady ) { + mOTotal = 0; + mOAvailable = 0; + emit didUSBSpaceChange(mCIsReady, mCTotal, mCAvailable, mPercent); + return; + } } - mOIsReady = mCIsReady ; - mOTotal = mCTotal ; - mOAvailable = mCAvailable ; - if (_pauseSpaceCheck) return; - emit didSDCardSpaceChange(mCIsReady, mCTotal, mCAvailable, mPercent); - /// DEBUG: qDebug() << Storage::SDCard_Base_Path_Name << mCIsReady << mCTotal << mCAvailable << mPercent ; + mPercent = mCTotal ? ((100 * mCAvailable) / mCTotal) : 0; + if (mOTotal != mCTotal || mOAvailable != mCAvailable) { + mOTotal = mCTotal ; + mOAvailable = mCAvailable ; + emit didUSBSpaceChange(mCIsReady, mCTotal, mCAvailable, mPercent); + } + + // DEBUG: qDebug() << "DeviceController::usbSpaceCheck" + // << mCIsReady + // << mCIsReadOnly + // << mCTotal + // << mCAvailable ; } -// coco end + /*! * \brief DeviceController::usbError * \details Logs any error which has been happened @@ -310,27 +366,27 @@ */ void DeviceController::usbError(const QString &vDevice) { - // coco begin validated: This needs user interaction to plug-in/out the USB device + // disabled coco begin validated: This needs user interaction to plug-in/out the USB device // has been tested manually QString error; static QString lastError; switch (errno) { case EBUSY: error = tr("%1 - Device or resource busy (%2)").arg(errno).arg(vDevice); _mounted = true; - break; + break; default: error = tr("%1 - %2 (%3 , %4)").arg(errno).arg(strerror(errno)).arg(vDevice).arg(USB_Mount_Point); - break; + break; } if (error != lastError) { LOG_DEBUG("USB: " + error); lastError = error; } } -// coco end +// disabled coco end /*! * \brief DeviceController::onUSBDriveUmount @@ -339,11 +395,11 @@ */ void DeviceController::onUSBDriveUmount() { - // coco begin validated: This needs user interaction to plug-in/out the USB device + // disabled coco begin validated: This needs user interaction to plug-in/out the USB device // has been tested manually _umounted = true; } -// coco end +// disabled coco end /*! * \brief DeviceController::usbMount @@ -352,24 +408,10 @@ * \param vDevice - USB device to be mounted (e.g. /dev/sda1) * \return true on successful mount */ -bool DeviceController::usbMount(const QString &vDevice) +void DeviceController::usbMount(const QString &vDevice) { - // coco begin validated: This needs user interaction to plug-in the USB device - // has been tested manually - bool ok; - _usbDrive = vDevice.toLatin1().constData(); - ok = ::mount(_usbDrive, USB_Mount_Point, USB_File_System, MS_SYNCHRONOUS, "") == 0; - if (ok) { - _mounted = true; - _removed = false; - LOG_DEBUG(QString("USB flash drive %1 has been mounted on %2").arg(vDevice).arg(USB_Mount_Point)); - emit didUSBDriveMount(); - } else { - usbError(vDevice); - } - return ok; + usbMountReq(vDevice); } -// coco end /*! * \brief DeviceController::usbUmount @@ -378,23 +420,10 @@ * \param vDevice - USB device to be unmounted (e.g. /dev/sda1) * \return true on successful unmount */ -bool DeviceController::usbUmount(const QString &vDevice) +void DeviceController::usbUmount(const QString &vDevice) { - // coco begin validated: This needs user interaction to plug-out the USB device - // has been tested manually - bool ok; - ok = ::umount(vDevice.toLatin1().constData()) == 0; - if (ok) { - _mounted = false; - LOG_DEBUG(QString("USB drive %2 unmounted").arg(vDevice)); - emit didUSBDriveUmount(); - } else { - // the error is irrelevant, commented out for now - //usbError(vDevice); - } - return ok; + usbMountReq(vDevice, false); } -// coco end /*! * \brief DeviceController::usbRemove @@ -404,15 +433,15 @@ */ void DeviceController::usbRemove() { - // coco begin validated: This needs user interaction to plug-out the USB device + // disabled coco begin validated: This needs user interaction to plug-out the USB device // has been tested manually usbUmount(USB_Mount_Point); _umounted = false; _removed = true; LOG_DEBUG("USB drive removed"); emit didUSBDriveRemove(); } -// coco end +// disabled coco end /*! * \brief DeviceController::checkError @@ -430,15 +459,16 @@ vModel._data.mAccepted = false ; vModel._data.mReason = vError ; vModel._data.mMessage = DeviceError::deviceErrorText(vError, vError); - LOG_EVENT(src + vModel._data.mMessage + " " + vExtraLogInfo); + LOG_APPED(" ," + src + vModel._data.mMessage + " " + vExtraLogInfo); emit didAttributeResponse(vModel._data); return true; } return false; } +///////////////////////////////////////////// DeviceBrightness /*! - * \brief DeviceController::doBrightness + * \brief DeviceController::onAttributeRequest * \details Sets the brightness level * \param vBrightness */ @@ -450,7 +480,7 @@ // ----- extract the required data _deviceBrightnessRequest.setBrightnessSysVal(); - LOG_EVENT( _deviceBrightnessRequest.toString()); + LOG_APPED( _deviceBrightnessRequest.toString()); // ----- check that script exists. QString script; @@ -496,11 +526,155 @@ _deviceBrightnessResponse.setBrightnessPercent(_deviceBrightnessRequest._data.mBrightness_val); _deviceBrightnessResponse._data.mMessage = _deviceBrightnessResponse.toString(); } - LOG_EVENT(_deviceBrightnessResponse._data.mMessage); + LOG_APPED(_deviceBrightnessResponse._data.mMessage); emit didAttributeResponse(_deviceBrightnessResponse._data); } } + +///////////////////////////////////////////// DeviceRootSSHAccess +/*! + * \brief DeviceController::onAttributeRequest + * \details Sets the RootSSHAccess + * \param vRootSSHAccess + */ +void DeviceController::onAttributeRequest(const DeviceRootSSHAccessRequestData &vData) +{ + // ----- initializing the member variable models + _deviceRootSSHAccessRequest._data = vData; + LOG_APPED( _deviceRootSSHAccessRequest.toString()); + + // ----- check that script exists. + QString script; + if ( checkError( DeviceError::checkScript(script, vData.mIsGet ? RootSSHAccess_Get : RootSSHAccess_Set), _deviceRootSSHAccessResponse, script) ) + return; + + // ----- check if the process is not running + if ( _processRootSSHAccess.state() != QProcess::NotRunning ) { + checkError(DeviceError::eDevice_Scripts_Error_IsRunning, _deviceRootSSHAccessResponse); + return; + } + + // ----- run the process + + TimedProcess *timedProcess = new TimedProcess(&_processRootSSHAccess, script, 1000, { _deviceRootSSHAccessRequest._data.mRootSSHAccess ? "YES": "no" }); + timedProcess->start(); +} + +/*! + * \brief DeviceController::onProcessRootSSHAccessExitCode + * \details Called when the process to set the RootSSHAccess has finished + * \param vExitCode (int) the exit code + * \note exit code -> 0 : set Accept [MBase] -> Log -> emit + * !0 : set Attrib [MBrgh] -> Log -> emit + * 1 - get an error when in onAttributeRequest : scriptErrorText([Gui Enum ]) + * 2 - get an error when in onProcessRootSSHAccessExitCode : scriptErrorText([vExitCode]) + * 3 - get no error when in onProcessRootSSHAccessExitCode : MDeviceResponse.toString() + * - in case 3 the specific model _data has to be filled prior to the toString to have it in the log. + */ +void DeviceController::onProcessRootSSHAccessExitCode(int vExitCode, QProcess::ExitStatus) +{ + if ( ! checkError(static_cast(vExitCode), _deviceRootSSHAccessResponse, _deviceRootSSHAccessResponse.toString()) ) { // has no error + if (_deviceRootSSHAccessRequest._data.mIsGet) { + bool ok = false; + bool rootSSHAccess = _processRootSSHAccess.readLine().toUInt(&ok); + if ( ok ) { + _deviceRootSSHAccessResponse._data.mMessage = _deviceRootSSHAccessResponse.toString(); + _deviceRootSSHAccessResponse._data.mRootSSHAccess = rootSSHAccess; + } + else { + checkError(DeviceError::eDevice_Scripts_Error_Incorrect_Rsp, _deviceRootSSHAccessResponse, _deviceRootSSHAccessResponse.toString()); + return; + } + } + else { + _deviceRootSSHAccessResponse._data.mMessage = _deviceRootSSHAccessResponse.toString(); + _deviceRootSSHAccessResponse._data.mRootSSHAccess = _deviceRootSSHAccessRequest._data.mRootSSHAccess; + } + LOG_APPED(_deviceRootSSHAccessResponse._data.mMessage); + emit didAttributeResponse(_deviceRootSSHAccessResponse._data); + } + else { + // the error in this case is handled in the checkError + } +} + +///////////////////////////////////////////// DeviceCryptSetup +/*! + * \brief DeviceController::onAttributeRequest + * \details Calls the CryptSetup script with the model data DeviceCryptSetupRequestData + * \param vData - the model data + */ +void DeviceController::onAttributeRequest(const DeviceCryptSetupRequestData &vData) +{ + //DEBUG qDebug() << " ---------- " << vData.mCommand << vData.mPassword; + + _deviceCryptSetupRequest._data = vData; + + // ----- check that script exists. + QString script; + if ( checkError( DeviceError::checkScript(script, Crypt_Setup), _deviceCryptSetupResponse, script) ) + return; + + // ----- check if the process is not running + if ( _processCryptSetup.state() != QProcess::NotRunning ) { + checkError(DeviceError::eDevice_Scripts_Error_IsRunning, _deviceCryptSetupResponse); + return; + } + + + // ----- run the process + int timeout = 10000; + TimedProcess *timedProcess = new TimedProcess(&_processCryptSetup, script, timeout, { _deviceCryptSetupRequest._data.mCommand }); + _processCryptSetup.setEnvironment(QProcess::systemEnvironment() << QString("PASSWORD=%1").arg(_deviceCryptSetupRequest._data.mPassword)); + timedProcess->start(); + + // Update UI with a response + MDeviceCryptSetupResponse model; + model._data.mAccepted = false; + model._data.mMessage = tr("Encrypted Partition %1 started.").arg(_deviceCryptSetupRequest._data.mCommand); + emit didAttributeResponse(model.data()); +} + +/*! + * \brief DeviceController::onProcessCryptSetupExitCode + * \param vExitCode + * \param vStatus + */ +void DeviceController::onProcessCryptSetupExitCode(int vExitCode, QProcess::ExitStatus vStatus) +{ + // The Exit code in this script is not used. + // any other checking is done by UI Software at the moment this script is called. + // The only thing matters is the pared device info in text and it will be empty string if error happens. + MDeviceCryptSetupResponse model; + QByteArray deviceInfo = _processCryptSetup.readAll(); + if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; + else deviceInfo = _processCryptSetup.readAll(); + model.fromByteArray( deviceInfo, &vExitCode ); + // DEBUG: qDebug() << model._data.mEchoInfo; + emit didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); + + if ( _deviceCryptSetupRequest._data.mCommand == "mount" ) emit didCryptSetupMount(model._data.mAccepted); + + // move the configuration files if the encrypted partition creation was successful. + if ( _deviceCryptSetupRequest._data.mCommand != "setup" ) return; + if ( ! model._data.mAccepted ) return; + QString msg = ""; + int err = 0 ; + //TODO The Settings shall be the Singleton SettingsController and modify the MSettings like the others. + Storage::Settings settings; + err = settings.configurationsMove(&msg); + if ( err ) { + model._data.mAccepted = false ; + model._data.mReason = err ; + model._data.mMessage = msg ; + emit didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); + } +} + +///////////////////////////////////////////// DeviceBluetoothPaired void DeviceController::onAttributeRequest(const DeviceBluetoothPairedResetRequestData &) { // ----- check that script exists. @@ -527,10 +701,11 @@ if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; else deviceInfo = _processBluetoothPairedReset.readAll(); model.fromByteArray( deviceInfo, &vExitCode ); - LOG_EVENT_UI(model.data().mMessage); - didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); + emit didAttributeResponse(model.data()); } +///////////////////////////////////////////// DeviceBluetoothPairedQuery void DeviceController::onAttributeRequest(const DeviceBluetoothPairedQueryRequestData &) { // ----- check that script exists. @@ -551,16 +726,16 @@ void DeviceController::onProcessBluetoothPairedQueryExitCode(int vExitCode, QProcess::ExitStatus vStatus) { - // The Exit code in this script is not used and is not used. + // The Exit code in this script is not used. // any other checking is done by UI Software at the moment this script is called. // The only thing matters is the pared device info in text and it will be empty string if error happens. MDeviceBluetoothPairedQueryResponse model; QByteArray deviceInfo; if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; else deviceInfo = _processBluetoothPairedQuery.readAll(); model.fromByteArray( deviceInfo, &vExitCode ); - didAttributeResponse(model.data()); - LOG_EVENT_UI(model.data().mMessage); + emit didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); } /*! @@ -591,7 +766,7 @@ void DeviceController::ondoAddWatch(const QString &vFile) { if ( ! QFileInfo::exists(vFile)) { - if ( ! FileHandler::write(vFile, "", false) ) { + if ( ! FileHandler::write(vFile, "", false) ) { // if the file doesn't exist it has to be created to be watched. LOG_DEBUG(DeviceError::deviceErrorText(DeviceError::eDevice_Watch_Error_NotFound, 0)); return; } @@ -610,3 +785,287 @@ { emit didWatchFileChange(vFile); } + +/*! + * \brief DeviceController::onEventThreadChange + * \details The signal handler for the DeviceController(this)::didEventThreadChange + * to start checking for the Encrypted partition readyness. + */ +void DeviceController::onEventThreadChange() +{ + //DEBUG qDebug() << " ---------- " << __FUNCTION__ << QThread::currentThread()->objectName() << QThread::currentThread() << qApp->thread(); + if ( QThread::currentThread() != &Threads::_DeviceController_Thread ) { + qCritical() << " ***** Device controller thread not initialized correctly ***** "; + return; + } + _hasThread = true; + checkConfugurationMountReady(); +} + +/*! + * \brief DeviceController::onPOSTEthernetData + * \details Collects the ethernet mac address + * when it is ready after the POST is done for the Ethernet + * \param vMacAddress - The Ethernet MAC address + */ +void DeviceController::onPOSTEthernetData(const QString &vMacAddress) { + _macEthernet = vMacAddress; + emit didPOSTEthernetData (vMacAddress); +} + +/*! + * \brief DeviceController::onPOSTWirelessData + * \details Collects the wireless mac address + * when it is ready after the POST is done for the Wireless connection + * \param vMacAddress - The Wireless MAC address + */ +void DeviceController::onPOSTWirelessData(const QString &vMacAddress) { + _macWireless = vMacAddress; + + encryption::varSalt(vMacAddress); + _hasSalt = ! vMacAddress.trimmed().isEmpty(); + checkConfugurationMountReady(); + + emit didPOSTWirelessData (vMacAddress); +} + +/*! + * \brief DeviceController::onPOSTBluetoothData + * \details Collects the bluetooth mac address + * when it is ready after the POST is done for the Bluetooth + * \param vMacAddress - The Bluetooth MAC address + */ +void DeviceController::onPOSTBluetoothData(const QString &vMacAddress) { + _macBluetooth = vMacAddress; + emit didPOSTBluetoothData (vMacAddress); +} + +/*! + * \brief DeviceController::onPOSTCloudSyncData + * \details Collects the CloudSync Network Address + * when it is ready after the POST is done for the CloudSync + * \param vNetAddress - *** Not defined yet and is a placeholder for later use *** + */ +void DeviceController::onPOSTCloudSyncData(const QString &vNetAddress) { + _netCloudSync = vNetAddress; + emit didPOSTCloudSyncData (vNetAddress); +} + +/*! + * \brief DeviceController::checkConfugurationMountReady + * \details Cheks if the system is ready to mount the encrypted partition. + * The object has to be on its own thread and the salt for the decryption has to be ready. + */ +void DeviceController::checkConfugurationMountReady() +{ + /// in manufacturing the system is logged with root and configurations are in /home/root + /// therefore no need to mount the cononfiguraiton partition. + /// also for in manufacturing the partition is being set up + /// and is less steps for setup if the partition is not mounted. + if ( gEnableManufacturing ) return; + + + if ( ! ( _hasThread && _hasSalt ) ) return; + + DeviceCryptSetupRequestData data; + data.mCommand = "mount"; + 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 { + onAttributeRequest(data); + } + + // I_AM_HERE + // HERE move the settings read from ApplicationController to here + // here is when the DeviceController is moved to its thread + // and now can start mounting the encrypted partition + // and then read the settings. + // TODO don't forget to check for the required configurations files and parameters in the settings class. + // and take care of the security flag in the Storage class. +} + +///////////////////////////////////////////// DeviceFactoryReset +void DeviceController::onAttributeRequest(const DeviceFactoryResetRequestData &vData) +{ + _deviceFactoryResetRequest._data = vData; + + // ----- check that script exists. + QString script; + if ( checkError( DeviceError::checkScript(script, Factory_Reset), _deviceFactoryResetResponse, script) ) + return; + + // ----- check if the process is not running + if ( _processFactoryReset.state() != QProcess::NotRunning ) { + checkError(DeviceError::eDevice_Scripts_Error_IsRunning, _deviceFactoryResetResponse); + return; + } + + + // ----- run the process + int timeout_ms = 10000; + TimedProcess *timedProcess = new TimedProcess(&_processFactoryReset, script, timeout_ms); + timedProcess->start(); + + MDeviceFactoryResetResponse model; + model._data.mAccepted = false; // will indirectly set the property factoryResetEnabled + model._data.mMessage = tr("Factory Reset started."); + didAttributeResponse(model.data()); +} + +/*! + * \brief DeviceController::onProcessFactoryResetExitCode + * \param vExitCode - the script exit code. + * \param vStatus - the script echoed message. + */ +void DeviceController::onProcessFactoryResetExitCode(int vExitCode, QProcess::ExitStatus vStatus) +{ + // The Exit code in this script is not used. + // any other checking is done by UI Software at the moment this script is called. + // The only thing matters is the paired device info in text and it will be empty string if error happens. + MDeviceFactoryResetResponse model; + QByteArray deviceInfo = _processFactoryReset.readAll(); + if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; + else deviceInfo = _processFactoryReset.readAll(); + model.fromByteArray( deviceInfo, &vExitCode ); + // DEBUG: qDebug() << model._data.mMessage << deviceInfo; + didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); +} + +///////////////////////////////////////////// DeviceDecommission +void DeviceController::onAttributeRequest(const DeviceDecommissionRequestData &vData) +{ + _deviceDecommissionRequest._data = vData; + + // ----- check that script exists. + QString script; + if ( checkError( DeviceError::checkScript(script, Device_Decommission), _deviceDecommissionResponse, script) ) + return; + + // ----- check if the process is not running + if ( _processDecommission.state() != QProcess::NotRunning ) { + checkError(DeviceError::eDevice_Scripts_Error_IsRunning, _deviceDecommissionResponse); + return; + } + + + // ----- run the process + int timeout_ms = 10000; + TimedProcess *timedProcess = new TimedProcess(&_processDecommission, script, timeout_ms, { CloudSyncPath }); + _processDecommission.setEnvironment(QProcess::systemEnvironment() << QString("PASSWORD=%1").arg(_deviceDecommissionRequest._data.mPassword)); + timedProcess->start(); + + MDeviceDecommissionResponse model; + model._data.mAccepted = false; // will indirectly set the property decommissionEnabled + model._data.mMessage = tr("Decommissioning started."); + didAttributeResponse(model.data()); +} + +/*! + * \brief DeviceController::onProcessDecommissionExitCode + * \param vExitCode + * \param vStatus + */ +void DeviceController::onProcessDecommissionExitCode(int vExitCode, QProcess::ExitStatus vStatus) +{ + // The Exit code in this script is not used. + // any other checking is done by UI Software at the moment this script is called. + // The only thing matters is the paired device info in text and it will be empty string if error happens. + MDeviceDecommissionResponse model; + QByteArray deviceInfo = _processDecommission.readAll(); + if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; + else deviceInfo = _processDecommission.readAll(); + model.fromByteArray( deviceInfo, &vExitCode ); + // DEBUG: qDebug() << model._data.mMessage << deviceInfo; + didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); +} + +///////////////////////////////////////////// DeviceUSBMounting +void DeviceController::onAttributeRequest(const DeviceUSBMountRequestData &vData) +{ + Q_UNUSED(vData) + usbMountReq(vData.usbDevice, vData.isMountRequest); +} + +/*! + * \brief DeviceController::usbMountReq + * \details Calls the Usb unmount/mount script + * \param vIsMount - indicate if the request is for mounting or unmounting + * \param vDevice - the path to the USB device + */ +void DeviceController::usbMountReq(const QString &vDevice, bool vIsMount) +{ + qDebug() << __FUNCTION__ << vDevice << vIsMount; + _deviceUSBMountRequest._data.isMountRequest = vIsMount ; + _deviceUSBMountRequest._data.usbDevice = vDevice ; // not necessary, but to be consistent + + // ----- check that script exists. + QString script; + if ( checkError( DeviceError::checkScript(script, (vIsMount ? USB_Mount : USB_Unmount )), _deviceUSBMountResponse, script) ) + return; + + // ----- check if the process is not running + if ( _processUSBMount.state() != QProcess::NotRunning ) { + checkError(DeviceError::eDevice_Scripts_Error_IsRunning, _deviceUSBMountResponse); + return; + } + + // ----- run the process + int timeout_ms = 5000; + TimedProcess *timedProcess = new TimedProcess(&_processUSBMount, script, timeout_ms, {vDevice, USB_Mount_Point, USB_File_System}); + timedProcess->start(); + + MDeviceUSBMountResponse model; + model._data.mAccepted = false; + model._data.mMessage = vIsMount ? tr("USB unmount started.") : tr("USB mount started"); + didAttributeResponse(model.data()); +} + +/*! + * \brief DeviceController::onProcessUSBMountExitCode + * \param vExitCode + * \param vStatus + */ +void DeviceController::onProcessUSBMountExitCode(int vExitCode, QProcess::ExitStatus vStatus) +{ + MDeviceUSBMountResponse model; + QByteArray deviceInfo = _processUSBMount.readAll(); + if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; + else deviceInfo = _processUSBMount.readAll(); + model.fromByteArray( deviceInfo, &vExitCode ); + didAttributeResponse(model.data()); + + // Re-evaluate the USB space available - need to call this here to avoid + // visual lag caused by waiting to call this function on the timer timeout + usbSpaceCheck(); + + bool ok = ! vStatus; + QString usbDevice = _deviceUSBMountRequest._data.usbDevice; + if(_deviceUSBMountRequest._data.isMountRequest) { // *** USB Mount + if ( ok ) { + _mounted = true; + _removed = false; + LOG_DEBUG(QString("USB flash drive %1 has been mounted on %2").arg(usbDevice).arg(USB_Mount_Point)); + emit didUSBDriveMount(); + } else { + usbError(usbDevice); + } + } else { // *** USB Unmount + if ( ok ) { + _mounted = false; + // _umounted = true; // I think it might be needed, but needs more testing. + LOG_DEBUG(QString("USB drive %2 unmounted").arg(usbDevice)); + emit didUSBDriveUmount(); + } else { + // the error is irrelevant, commented out for now + // usbError(usbDrive); + } + } + + // log error and exit + return; +}