File indexing completed on 2024-05-19 05:35:37

0001 # SPDX-License-Identifier: GPL-3.0-or-later
0002 # SPDX-FileCopyrightText: 2021 Anupam Basak <anupam.basak27@gmail.com>
0003 
0004 import os
0005 import re
0006 
0007 from PySide2.QtCore import QUrl, Slot, Signal, Property, QObject, QProcess
0008 from PySide2.QtQml import qmlRegisterType
0009 
0010 from PicoWizard.module import Module
0011 from PicoWizard.modules.wifi.wifimodel import WifiModel
0012 from PicoWizard.utils.logger import Logger
0013 
0014 
0015 class Wifi(Module):
0016     log = Logger.getLogger(__name__)
0017 
0018     def __init__(self, parent=None):
0019         super().__init__(__file__, parent)
0020 
0021         self._wifiModel = WifiModel(parent)
0022 
0023         self.listWifi()
0024 
0025     @staticmethod
0026     def registerTypes() -> None:
0027         qmlRegisterType(Wifi, 'PicoWizard', 1, 0, 'WifiModule')
0028 
0029     @staticmethod
0030     def qmlPath() -> QUrl:
0031         return QUrl(os.path.join(os.path.dirname(os.path.realpath(__file__)), "Wifi.qml"))
0032 
0033     @Slot(None, result=str)
0034     def moduleName(self) -> str:
0035         return self.tr("Wifi")
0036 
0037     @Signal
0038     def modelChanged(self):
0039         pass
0040 
0041     @Property(QObject, notify=modelChanged)
0042     def model(self):
0043         return self._wifiModel
0044 
0045     def listWifi(self):
0046         self.log.info('Fetching list of wifi')
0047 
0048         args = [
0049             '/usr/bin/nmcli',
0050             '-c',
0051             'no',
0052             '-f',
0053             'BSSID,SSID,SIGNAL,SECURITY',
0054             '-t',
0055             'dev',
0056             'wifi',
0057             'list',
0058             '--rescan',
0059             'yes'
0060         ]
0061 
0062         process = QProcess(self)
0063         process.start('/usr/bin/pkexec', args)
0064 
0065         process.finished.connect(lambda exitCode, exitStatus: self.listWifiProcessFinished(process, exitCode, exitStatus))
0066         process.errorOccurred.connect(lambda err: self.listWifiProcessError(process, err))
0067 
0068     def listWifiProcessFinished(self, process, exitCode, exitStatus):
0069         self.log.debug(f'List Wifi process status : {exitStatus}[CODE {exitCode}]')
0070         self.log.info('Listing Wifi')
0071 
0072         output = process.readAll().data().decode()
0073 
0074         if exitCode != 0 or "Error:" in output:
0075             self.log.error(f'Failed to get wifi list : {exitStatus}')
0076             self.errorOccurred.emit("Error listing wifi connections")
0077         else:
0078             self.log.debug('Parsing wifi data')
0079             self.generateWifiList(output)
0080 
0081     def listWifiProcessError(self, process, err):
0082         self.log.error(f'Failed to get wifi list : {err}')
0083 
0084     def generateWifiList(self, output):
0085         self._wifiModel.reset()
0086         wifiItemRegex = '(.*):(.*):(.*):(.*)'
0087         matches = re.findall(wifiItemRegex, output)
0088 
0089         for match in matches:
0090             if match[1]:
0091                 wifiItem = {
0092                     'bssid': match[0].replace('\\', ''),
0093                     'ssid': match[1],
0094                     'signal': match[2],
0095                     'security': match[3] if match[3] else 'Open',
0096                     'isSecured': True if match[3] else False
0097                 }
0098 
0099                 self._wifiModel.layoutAboutToBeChanged.emit()
0100                 self._wifiModel.addWifiItem(wifiItem)
0101                 self._wifiModel.layoutChanged.emit()
0102 
0103         self.log.info('Generated Wifi List')
0104         self.log.debug(self._wifiModel.getWifiList())
0105 
0106     @Slot(int, str, result=None)
0107     def setWifi(self, wifiIndex, password):
0108         bssid = self._wifiModel.data(self._wifiModel.index(wifiIndex, 0), WifiModel.BssidRole)
0109         ssid = self._wifiModel.data(self._wifiModel.index(wifiIndex, 0), WifiModel.SsidRole)
0110         self.log.debug(f'Selected SSID : {ssid}')
0111 
0112         process = QProcess(self)
0113         args = [
0114             '/usr/bin/nmcli',
0115             'dev',
0116             'wifi',
0117             'connect',
0118             f'{ssid}',
0119             'password',
0120             f'{password}',
0121             'bssid',
0122             f'{bssid}'
0123         ]
0124 
0125         process.start('/usr/bin/pkexec', args)
0126 
0127         process.finished.connect(lambda exitCode, exitStatus: self.setWifiCmdSuccess(process, exitCode, exitStatus, ssid))
0128         process.error.connect(lambda err: self.setWifiCmdFailed(process, err))
0129 
0130     def setWifiCmdSuccess(self, process, exitCode, exitStatus, ssid):
0131         self.log.debug(f'Connect Wifi process status : {exitStatus} [CODE {exitCode}]')
0132 
0133         output = process.readAll().data().decode()
0134 
0135         if exitCode != 0 or "Error:" in output:
0136             self.log.error(f'Failed to connect to wifi : {output} [{exitStatus}]')
0137             self.errorOccurred.emit("Failed to connect to wifi. Recheck the password and try again.")
0138             self.connectWifiFailed.emit()
0139         else:
0140             self.log.info("Successfully connected to wifi")
0141             Module.__ENV__.insert('PICOWIZARD_WIFI', ssid)
0142             self.connectWifiSuccess.emit()
0143 
0144     def setWifiCmdFailed(self, process, err):
0145         self.log.error(f'Failed to connect to wifi : {err}')
0146         self.errorOccurred.emit("Failed to connect to wifi")
0147         self.connectWifiFailed.emit()
0148 
0149     @Signal
0150     def connectWifiSuccess(self):
0151         pass
0152 
0153     @Signal
0154     def connectWifiFailed(self):
0155         pass