diff options
Diffstat (limited to 'services')
| -rw-r--r-- | services/Nmcli.qml | 624 |
1 files changed, 333 insertions, 291 deletions
diff --git a/services/Nmcli.qml b/services/Nmcli.qml index a9f9e8e..24a93da 100644 --- a/services/Nmcli.qml +++ b/services/Nmcli.qml @@ -1,4 +1,5 @@ pragma Singleton +pragma ComponentBehavior: Bound import Quickshell import Quickshell.Io @@ -19,7 +20,7 @@ Singleton { readonly property AccessPoint active: networks.find(n => n.active) ?? null property list<string> savedConnections: [] property list<string> savedConnectionSsids: [] - + property var wifiConnectionQueue: [] property int currentSsidQueryIndex: 0 property var pendingConnection: null @@ -28,9 +29,8 @@ Singleton { property var ethernetDeviceDetails: null property list<var> ethernetDevices: [] readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null - + property list<var> activeProcesses: [] - property var debugLogger: null // Constants readonly property string deviceTypeWifi: "wifi" @@ -55,63 +55,35 @@ Singleton { readonly property string connectionParamPassword: "password" readonly property string connectionParamBssid: "802-11-wireless.bssid" - function setDebugLogger(logger: var): void { - root.debugLogger = logger; - } - - function log(message: string): void { - if (root.debugLogger) { - root.debugLogger(message); - } else { - console.log("[Nmcli]", message); - } - } - - function appendLog(message: string): void { - log(message); - } - function detectPasswordRequired(error: string): bool { if (!error || error.length === 0) { return false; } - - return (error.includes("Secrets were required") || - error.includes("Secrets were required, but not provided") || - error.includes("No secrets provided") || - error.includes("802-11-wireless-security.psk") || - error.includes("password for") || - (error.includes("password") && !error.includes("Connection activated") && !error.includes("successfully")) || - (error.includes("Secrets") && !error.includes("Connection activated") && !error.includes("successfully")) || - (error.includes("802.11") && !error.includes("Connection activated") && !error.includes("successfully"))) && - !error.includes("Connection activated") && - !error.includes("successfully"); + + return (error.includes("Secrets were required") || error.includes("Secrets were required, but not provided") || error.includes("No secrets provided") || error.includes("802-11-wireless-security.psk") || error.includes("password for") || (error.includes("password") && !error.includes("Connection activated") && !error.includes("successfully")) || (error.includes("Secrets") && !error.includes("Connection activated") && !error.includes("successfully")) || (error.includes("802.11") && !error.includes("Connection activated") && !error.includes("successfully"))) && !error.includes("Connection activated") && !error.includes("successfully"); } function parseNetworkOutput(output: string): list<var> { if (!output || output.length === 0) { return []; } - + const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED"; const rep = new RegExp("\\\\:", "g"); const rep2 = new RegExp(PLACEHOLDER, "g"); - - const allNetworks = output.trim().split("\n") - .filter(line => line && line.length > 0) - .map(n => { - const net = n.replace(rep, PLACEHOLDER).split(":"); - return { - active: net[0] === "yes", - strength: parseInt(net[1] || "0", 10) || 0, - frequency: parseInt(net[2] || "0", 10) || 0, - ssid: (net[3]?.replace(rep2, ":") ?? "").trim(), - bssid: (net[4]?.replace(rep2, ":") ?? "").trim(), - security: (net[5] ?? "").trim() - }; - }) - .filter(n => n.ssid && n.ssid.length > 0); - + + const allNetworks = output.trim().split("\n").filter(line => line && line.length > 0).map(n => { + const net = n.replace(rep, PLACEHOLDER).split(":"); + return { + active: net[0] === "yes", + strength: parseInt(net[1] || "0", 10) || 0, + frequency: parseInt(net[2] || "0", 10) || 0, + ssid: (net[3]?.replace(rep2, ":") ?? "").trim(), + bssid: (net[4]?.replace(rep2, ":") ?? "").trim(), + security: (net[5] ?? "").trim() + }; + }).filter(n => n.ssid && n.ssid.length > 0); + return allNetworks; } @@ -119,7 +91,7 @@ Singleton { if (!networks || networks.length === 0) { return []; } - + const networkMap = new Map(); for (const network of networks) { const existing = networkMap.get(network.ssid); @@ -135,7 +107,7 @@ Singleton { } } } - + return Array.from(networkMap.values()); } @@ -143,7 +115,7 @@ Singleton { if (!command || command.length === 0) { return false; } - + return command.includes(root.nmcliCommandWifi) || command.includes(root.nmcliCommandConnection); } @@ -151,16 +123,16 @@ Singleton { if (!output || output.length === 0) { return []; } - + const interfaces = []; const lines = output.trim().split("\n"); - + for (const line of lines) { const parts = line.split(":"); if (parts.length >= 2) { const deviceType = parts[1]; let shouldInclude = false; - + if (filterType === root.deviceTypeWifi && deviceType === root.deviceTypeWifi) { shouldInclude = true; } else if (filterType === root.deviceTypeEthernet && deviceType === root.deviceTypeEthernet) { @@ -168,7 +140,7 @@ Singleton { } else if (filterType === "both" && (deviceType === root.deviceTypeWifi || deviceType === root.deviceTypeEthernet)) { shouldInclude = true; } - + if (shouldInclude) { interfaces.push({ device: parts[0] || "", @@ -179,7 +151,7 @@ Singleton { } } } - + return interfaces; } @@ -187,53 +159,53 @@ Singleton { if (!state || state.length === 0) { return false; } - - return state === "100 (connected)" || - state === "connected" || - state.startsWith("connected"); + + return state === "100 (connected)" || state === "connected" || state.startsWith("connected"); } function executeCommand(args: list<string>, callback: var): void { const proc = commandProc.createObject(root); proc.command = ["nmcli", ...args]; proc.callback = callback; - + activeProcesses.push(proc); - + proc.processFinished.connect(() => { const index = activeProcesses.indexOf(proc); if (index >= 0) { activeProcesses.splice(index, 1); } }); - + Qt.callLater(() => { proc.exec(proc.command); }); } function getDeviceStatus(callback: var): void { - executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], (result) => { - if (callback) callback(result.output); + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + if (callback) + callback(result.output); }); } function getWirelessInterfaces(callback: var): void { - executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], (result) => { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeWifi); root.wirelessInterfaces = interfaces; - if (callback) callback(interfaces); + if (callback) + callback(interfaces); }); } function getEthernetInterfaces(callback: var): void { - executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], (result) => { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeEthernet); const devices = []; - + for (const iface of interfaces) { const connected = isConnectedState(iface.state); - + devices.push({ interface: iface.device, type: iface.type, @@ -248,16 +220,17 @@ Singleton { speed: "" }); } - + root.ethernetInterfaces = interfaces; root.ethernetDevices = devices; - if (callback) callback(interfaces); + if (callback) + callback(interfaces); }); } function connectEthernet(connectionName: string, interfaceName: string, callback: var): void { if (connectionName && connectionName.length > 0) { - executeCommand([root.nmcliCommandConnection, "up", connectionName], (result) => { + executeCommand([root.nmcliCommandConnection, "up", connectionName], result => { if (result.success) { Qt.callLater(() => { getEthernetInterfaces(() => {}); @@ -268,10 +241,11 @@ Singleton { } }, 500); } - if (callback) callback(result); + if (callback) + callback(result); }); } else if (interfaceName && interfaceName.length > 0) { - executeCommand([root.nmcliCommandDevice, "connect", interfaceName], (result) => { + executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => { if (result.success) { Qt.callLater(() => { getEthernetInterfaces(() => {}); @@ -280,62 +254,94 @@ Singleton { }, 1000); }, 500); } - if (callback) callback(result); + if (callback) + callback(result); }); } else { - if (callback) callback({ success: false, output: "", error: "No connection name or interface specified", exitCode: -1 }); + if (callback) + callback({ + success: false, + output: "", + error: "No connection name or interface specified", + exitCode: -1 + }); } } function disconnectEthernet(connectionName: string, callback: var): void { if (!connectionName || connectionName.length === 0) { - if (callback) callback({ success: false, output: "", error: "No connection name specified", exitCode: -1 }); + if (callback) + callback({ + success: false, + output: "", + error: "No connection name specified", + exitCode: -1 + }); return; } - - executeCommand([root.nmcliCommandConnection, "down", connectionName], (result) => { + + executeCommand([root.nmcliCommandConnection, "down", connectionName], result => { if (result.success) { root.ethernetDeviceDetails = null; Qt.callLater(() => { getEthernetInterfaces(() => {}); }, 500); } - if (callback) callback(result); + if (callback) + callback(result); }); } function getAllInterfaces(callback: var): void { - executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], (result) => { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { const interfaces = parseDeviceStatusOutput(result.output, "both"); - if (callback) callback(interfaces); + if (callback) + callback(interfaces); }); } function isInterfaceConnected(interfaceName: string, callback: var): void { - executeCommand([root.nmcliCommandDevice, "status"], (result) => { + executeCommand([root.nmcliCommandDevice, "status"], result => { const lines = result.output.trim().split("\n"); for (const line of lines) { const parts = line.split(/\s+/); if (parts.length >= 3 && parts[0] === interfaceName) { const connected = isConnectedState(parts[2]); - if (callback) callback(connected); + if (callback) + callback(connected); return; } } - if (callback) callback(false); + if (callback) + callback(false); }); } function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void { if (isSecure) { const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; - connectWireless(ssid, "", bssid, (result) => { + connectWireless(ssid, "", bssid, result => { if (result.success) { - if (callback) callback({ success: true, usedSavedPassword: true, output: result.output, error: "", exitCode: 0 }); + if (callback) + callback({ + success: true, + usedSavedPassword: true, + output: result.output, + error: "", + exitCode: 0 + }); } else if (result.needsPassword) { - if (callback) callback({ success: false, needsPassword: true, output: result.output, error: result.error, exitCode: result.exitCode }); + if (callback) + callback({ + success: false, + needsPassword: true, + output: result.output, + error: result.error, + exitCode: result.exitCode + }); } else { - if (callback) callback(result); + if (callback) + callback(result); } }); } else { @@ -351,72 +357,68 @@ Singleton { const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; const retries = retryCount !== undefined ? retryCount : 0; const maxRetries = 2; - + if (callback) { - root.pendingConnection = { ssid: ssid, bssid: hasBssid ? bssid : "", callback: callback, retryCount: retries }; + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback, + retryCount: retries + }; connectionCheckTimer.start(); immediateCheckTimer.checkCount = 0; immediateCheckTimer.start(); } - + if (password && password.length > 0 && hasBssid) { const bssidUpper = bssid.toUpperCase(); createConnectionWithPassword(ssid, bssidUpper, password, callback); return; } - + let cmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid]; if (password && password.length > 0) { cmd.push(root.connectionParamPassword, password); } - executeCommand(cmd, (result) => { + executeCommand(cmd, result => { if (result.needsPassword && callback) { - if (callback) callback(result); + if (callback) + callback(result); return; } - + if (!result.success && root.pendingConnection && retries < maxRetries) { - log("Connection failed, retrying... (attempt " + (retries + 1) + "/" + maxRetries + ")"); + console.warn("[NMCLI] Connection failed, retrying... (attempt " + (retries + 1) + "/" + maxRetries + ")"); Qt.callLater(() => { connectWireless(ssid, password, bssid, callback, retries + 1); }, 1000); - } else if (!result.success && root.pendingConnection) { - } else if (result.success && callback) { - } else if (!result.success && !root.pendingConnection) { - if (callback) callback(result); + } else if (!result.success && root.pendingConnection) {} else if (result.success && callback) {} else if (!result.success && !root.pendingConnection) { + if (callback) + callback(result); } }); } function createConnectionWithPassword(ssid: string, bssidUpper: string, password: string, callback: var): void { checkAndDeleteConnection(ssid, () => { - const cmd = [root.nmcliCommandConnection, "add", - root.connectionParamType, root.deviceTypeWifi, - root.connectionParamConName, ssid, - root.connectionParamIfname, "*", - root.connectionParamSsid, ssid, - root.connectionParamBssid, bssidUpper, - root.securityKeyMgmt, root.keyMgmtWpaPsk, - root.securityPsk, password]; - - executeCommand(cmd, (result) => { + const cmd = [root.nmcliCommandConnection, "add", root.connectionParamType, root.deviceTypeWifi, root.connectionParamConName, ssid, root.connectionParamIfname, "*", root.connectionParamSsid, ssid, root.connectionParamBssid, bssidUpper, root.securityKeyMgmt, root.keyMgmtWpaPsk, root.securityPsk, password]; + + executeCommand(cmd, result => { if (result.success) { loadSavedConnections(() => {}); activateConnection(ssid, callback); } else { - const hasDuplicateWarning = result.error && ( - result.error.includes("another connection with the name") || - result.error.includes("Reference the connection by its uuid") - ); - + const hasDuplicateWarning = result.error && (result.error.includes("another connection with the name") || result.error.includes("Reference the connection by its uuid")); + if (hasDuplicateWarning || (result.exitCode > 0 && result.exitCode < 10)) { loadSavedConnections(() => {}); activateConnection(ssid, callback); } else { - log("Connection profile creation failed, trying fallback..."); + console.warn("[NMCLI] Connection profile creation failed, trying fallback..."); let fallbackCmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid, root.connectionParamPassword, password]; - executeCommand(fallbackCmd, (fallbackResult) => { - if (callback) callback(fallbackResult); + executeCommand(fallbackCmd, fallbackResult => { + if (callback) + callback(fallbackResult); }); } } @@ -425,34 +427,38 @@ Singleton { } function checkAndDeleteConnection(ssid: string, callback: var): void { - executeCommand([root.nmcliCommandConnection, "show", ssid], (result) => { + executeCommand([root.nmcliCommandConnection, "show", ssid], result => { if (result.success) { - executeCommand([root.nmcliCommandConnection, "delete", ssid], (deleteResult) => { + executeCommand([root.nmcliCommandConnection, "delete", ssid], deleteResult => { Qt.callLater(() => { - if (callback) callback(); + if (callback) + callback(); }, 300); }); } else { - if (callback) callback(); + if (callback) + callback(); } }); } function activateConnection(connectionName: string, callback: var): void { - executeCommand([root.nmcliCommandConnection, "up", connectionName], (result) => { - if (callback) callback(result); + executeCommand([root.nmcliCommandConnection, "up", connectionName], result => { + if (callback) + callback(result); }); } function loadSavedConnections(callback: var): void { - executeCommand(["-t", "-f", root.connectionListFields, root.nmcliCommandConnection, "show"], (result) => { + executeCommand(["-t", "-f", root.connectionListFields, root.nmcliCommandConnection, "show"], result => { if (!result.success) { root.savedConnections = []; root.savedConnectionSsids = []; - if (callback) callback([]); + if (callback) + callback([]); return; } - + parseConnectionList(result.output, callback); }); } @@ -461,22 +467,22 @@ Singleton { const lines = output.trim().split("\n").filter(line => line.length > 0); const wifiConnections = []; const connections = []; - + for (const line of lines) { const parts = line.split(":"); if (parts.length >= 2) { const name = parts[0]; const type = parts[1]; connections.push(name); - + if (type === root.connectionTypeWireless) { wifiConnections.push(name); } } } - + root.savedConnections = connections; - + if (wifiConnections.length > 0) { root.wifiConnectionQueue = wifiConnections; root.currentSsidQueryIndex = 0; @@ -485,7 +491,8 @@ Singleton { } else { root.savedConnectionSsids = []; root.wifiConnectionQueue = []; - if (callback) callback(root.savedConnectionSsids); + if (callback) + callback(root.savedConnectionSsids); } } @@ -493,8 +500,8 @@ Singleton { if (root.currentSsidQueryIndex < root.wifiConnectionQueue.length) { const connectionName = root.wifiConnectionQueue[root.currentSsidQueryIndex]; root.currentSsidQueryIndex++; - - executeCommand(["-t", "-f", root.wirelessSsidField, root.nmcliCommandConnection, "show", connectionName], (result) => { + + executeCommand(["-t", "-f", root.wirelessSsidField, root.nmcliCommandConnection, "show", connectionName], result => { if (result.success) { processSsidOutput(result.output); } @@ -503,7 +510,8 @@ Singleton { } else { root.wifiConnectionQueue = []; root.currentSsidQueryIndex = 0; - if (callback) callback(root.savedConnectionSsids); + if (callback) + callback(root.savedConnectionSsids); } } @@ -530,70 +538,73 @@ Singleton { return false; } const ssidLower = ssid.toLowerCase().trim(); - + if (root.active && root.active.ssid) { const activeSsidLower = root.active.ssid.toLowerCase().trim(); if (activeSsidLower === ssidLower) { return true; } } - - const hasSsid = root.savedConnectionSsids.some(savedSsid => - savedSsid && savedSsid.toLowerCase().trim() === ssidLower - ); - + + const hasSsid = root.savedConnectionSsids.some(savedSsid => savedSsid && savedSsid.toLowerCase().trim() === ssidLower); + if (hasSsid) { return true; } - - const hasConnectionName = root.savedConnections.some(connName => - connName && connName.toLowerCase().trim() === ssidLower - ); - + + const hasConnectionName = root.savedConnections.some(connName => connName && connName.toLowerCase().trim() === ssidLower); + return hasConnectionName; } function forgetNetwork(ssid: string, callback: var): void { if (!ssid || ssid.length === 0) { - if (callback) callback({ success: false, output: "", error: "No SSID specified", exitCode: -1 }); + if (callback) + callback({ + success: false, + output: "", + error: "No SSID specified", + exitCode: -1 + }); return; } - - const connectionName = root.savedConnections.find(conn => - conn && conn.toLowerCase().trim() === ssid.toLowerCase().trim() - ) || ssid; - - executeCommand([root.nmcliCommandConnection, "delete", connectionName], (result) => { + + const connectionName = root.savedConnections.find(conn => conn && conn.toLowerCase().trim() === ssid.toLowerCase().trim()) || ssid; + + executeCommand([root.nmcliCommandConnection, "delete", connectionName], result => { if (result.success) { Qt.callLater(() => { loadSavedConnections(() => {}); }, 500); } - if (callback) callback(result); + if (callback) + callback(result); }); } function disconnect(interfaceName: string, callback: var): void { if (interfaceName && interfaceName.length > 0) { - executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], (result) => { - if (callback) callback(result.success ? result.output : ""); + executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => { + if (callback) + callback(result.success ? result.output : ""); }); } else { - executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], (result) => { - if (callback) callback(result.success ? result.output : ""); + executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => { + if (callback) + callback(result.success ? result.output : ""); }); } } function disconnectFromNetwork(): void { if (active && active.ssid) { - executeCommand([root.nmcliCommandConnection, "down", active.ssid], (result) => { + executeCommand([root.nmcliCommandConnection, "down", active.ssid], result => { if (result.success) { getNetworks(() => {}); } }); } else { - executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], (result) => { + executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => { if (result.success) { getNetworks(() => {}); } @@ -602,13 +613,14 @@ Singleton { } function getDeviceDetails(interfaceName: string, callback: var): void { - executeCommand([root.nmcliCommandDevice, "show", interfaceName], (result) => { - if (callback) callback(result.output); + executeCommand([root.nmcliCommandDevice, "show", interfaceName], result => { + if (callback) + callback(result.output); }); } function refreshStatus(callback: var): void { - getDeviceStatus((output) => { + getDeviceStatus(output => { const lines = output.trim().split("\n"); let connected = false; let activeIf = ""; @@ -631,31 +643,48 @@ Singleton { root.activeInterface = activeIf; root.activeConnection = activeConn; - if (callback) callback({ connected, interface: activeIf, connection: activeConn }); + if (callback) + callback({ + connected, + interface: activeIf, + connection: activeConn + }); }); } function bringInterfaceUp(interfaceName: string, callback: var): void { if (interfaceName && interfaceName.length > 0) { - executeCommand([root.nmcliCommandDevice, "connect", interfaceName], (result) => { + executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => { if (callback) { callback(result); } }); } else { - if (callback) callback({ success: false, output: "", error: "No interface specified", exitCode: -1 }); + if (callback) + callback({ + success: false, + output: "", + error: "No interface specified", + exitCode: -1 + }); } } function bringInterfaceDown(interfaceName: string, callback: var): void { if (interfaceName && interfaceName.length > 0) { - executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], (result) => { + executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => { if (callback) { callback(result); } }); } else { - if (callback) callback({ success: false, output: "", error: "No interface specified", exitCode: -1 }); + if (callback) + callback({ + success: false, + output: "", + error: "No interface specified", + exitCode: -1 + }); } } @@ -664,7 +693,7 @@ Singleton { if (interfaceName && interfaceName.length > 0) { cmd.push(root.connectionParamIfname, interfaceName); } - executeCommand(cmd, (result) => { + executeCommand(cmd, result => { if (callback) { callback(result); } @@ -677,14 +706,16 @@ Singleton { function enableWifi(enabled: bool, callback: var): void { const cmd = enabled ? "on" : "off"; - executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi, cmd], (result) => { + executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi, cmd], result => { if (result.success) { - getWifiStatus((status) => { + getWifiStatus(status => { root.wifiEnabled = status; - if (callback) callback(result); + if (callback) + callback(result); }); } else { - if (callback) callback(result); + if (callback) + callback(result); } }); } @@ -695,33 +726,32 @@ Singleton { } function getWifiStatus(callback: var): void { - executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi], (result) => { + executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi], result => { if (result.success) { const enabled = result.output.trim() === "enabled"; root.wifiEnabled = enabled; - if (callback) callback(enabled); + if (callback) + callback(enabled); } else { - if (callback) callback(root.wifiEnabled); + if (callback) + callback(root.wifiEnabled); } }); } function getNetworks(callback: var): void { - executeCommand(["-g", root.networkDetailFields, "d", "w"], (result) => { + executeCommand(["-g", root.networkDetailFields, "d", "w"], result => { if (!result.success) { - if (callback) callback([]); + if (callback) + callback([]); return; } - + const allNetworks = parseNetworkOutput(result.output); const networks = deduplicateNetworks(allNetworks); const rNetworks = root.networks; - - const destroyed = rNetworks.filter(rn => !networks.find(n => - n.frequency === rn.frequency && - n.ssid === rn.ssid && - n.bssid === rn.bssid - )); + + const destroyed = rNetworks.filter(rn => !networks.find(n => n.frequency === rn.frequency && n.ssid === rn.ssid && n.bssid === rn.bssid)); for (const network of destroyed) { const index = rNetworks.indexOf(network); if (index >= 0) { @@ -729,13 +759,9 @@ Singleton { network.destroy(); } } - + for (const network of networks) { - const match = rNetworks.find(n => - n.frequency === network.frequency && - n.ssid === network.ssid && - n.bssid === network.bssid - ); + const match = rNetworks.find(n => n.frequency === network.frequency && n.ssid === network.ssid && n.bssid === network.bssid); if (match) { match.lastIpcObject = network; } else { @@ -744,8 +770,9 @@ Singleton { })); } } - - if (callback) callback(root.networks); + + if (callback) + callback(root.networks); checkPendingConnection(); }); } @@ -755,19 +782,21 @@ Singleton { if (interfaceName && interfaceName.length > 0) { cmd.push(root.connectionParamIfname, interfaceName); } - executeCommand(cmd, (result) => { + executeCommand(cmd, result => { if (!result.success) { - if (callback) callback([]); + if (callback) + callback([]); return; } - + const ssids = []; const lines = result.output.trim().split("\n"); const seenSSIDs = new Set(); - + for (const line of lines) { - if (!line || line.length === 0) continue; - + if (!line || line.length === 0) + continue; + const parts = line.split(":"); if (parts.length >= 1) { const ssid = parts[0].trim(); @@ -785,12 +814,13 @@ Singleton { } } } - + ssids.sort((a, b) => { return b.signalValue - a.signalValue; }); - - if (callback) callback(ssids); + + if (callback) + callback(ssids); }); } @@ -798,13 +828,13 @@ Singleton { if (!proc || !error || error.length === 0) { return false; } - + if (!isConnectionCommand(proc.command) || !root.pendingConnection || !root.pendingConnection.callback) { return false; } - + const needsPassword = detectPasswordRequired(error); - + if (needsPassword && !proc.callbackCalled && root.pendingConnection) { connectionCheckTimer.stop(); immediateCheckTimer.stop(); @@ -827,77 +857,79 @@ Singleton { } return true; } - + return false; } component CommandProcess: Process { id: proc + property var callback: null property list<string> command: [] property bool callbackCalled: false property int exitCode: 0 + signal processFinished environment: ({ - LANG: "C.UTF-8", - LC_ALL: "C.UTF-8" - }) + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) stdout: StdioCollector { id: stdoutCollector - onStreamFinished: { - } } stderr: StdioCollector { id: stderrCollector + onStreamFinished: { const error = text.trim(); if (error && error.length > 0) { const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; - handlePasswordRequired(proc, error, output, -1); + root.handlePasswordRequired(proc, error, output, -1); } } } - onExited: { - proc.exitCode = exitCode; + onExited: code => { + exitCode = code; + Qt.callLater(() => { - if (proc.callbackCalled) { - proc.processFinished(); + if (callbackCalled) { + processFinished(); return; } - + if (proc.callback) { const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : ""; - const success = proc.exitCode === 0; + const success = exitCode === 0; const cmdIsConnection = isConnectionCommand(proc.command); - - if (handlePasswordRequired(proc, error, output, proc.exitCode)) { - proc.processFinished(); + + if (root.handlePasswordRequired(proc, error, output, exitCode)) { + processFinished(); return; } - - const needsPassword = cmdIsConnection && detectPasswordRequired(error); - + + const needsPassword = cmdIsConnection && root.detectPasswordRequired(error); + if (!success && cmdIsConnection && root.pendingConnection) { const failedSsid = root.pendingConnection.ssid; root.connectionFailed(failedSsid); } - - proc.callbackCalled = true; - proc.callback({ + + callbackCalled = true; + callback({ success: success, output: output, error: error, exitCode: proc.exitCode, needsPassword: needsPassword || false }); - proc.processFinished(); + processFinished(); } else { - proc.processFinished(); + processFinished(); } }); } @@ -905,6 +937,7 @@ Singleton { Component { id: commandProc + CommandProcess {} } @@ -921,16 +954,18 @@ Singleton { Component { id: apComp + AccessPoint {} } Timer { id: connectionCheckTimer + interval: 4000 onTriggered: { if (root.pendingConnection) { const connected = root.active && root.active.ssid === root.pendingConnection.ssid; - + if (!connected && root.pendingConnection.callback) { let foundPasswordError = false; for (let i = 0; i < root.activeProcesses.length; i++) { @@ -938,9 +973,9 @@ Singleton { if (proc && proc.stderr && proc.stderr.text) { const error = proc.stderr.text.trim(); if (error && error.length > 0) { - if (isConnectionCommand(proc.command)) { - const needsPassword = detectPasswordRequired(error); - + if (root.isConnectionCommand(proc.command)) { + const needsPassword = root.detectPasswordRequired(error); + if (needsPassword && !proc.callbackCalled && root.pendingConnection) { const pending = root.pendingConnection; root.pendingConnection = null; @@ -967,7 +1002,7 @@ Singleton { } } } - + if (!foundPasswordError) { const pending = root.pendingConnection; const failedSsid = pending.ssid; @@ -975,10 +1010,10 @@ Singleton { immediateCheckTimer.stop(); immediateCheckTimer.checkCount = 0; root.connectionFailed(failedSsid); - pending.callback({ - success: false, - output: "", - error: "Connection timeout", + pending.callback({ + success: false, + output: "", + error: "Connection timeout", exitCode: -1, needsPassword: false }); @@ -994,22 +1029,29 @@ Singleton { Timer { id: immediateCheckTimer + + property int checkCount: 0 + interval: 500 repeat: true triggeredOnStart: false - property int checkCount: 0 onTriggered: { if (root.pendingConnection) { checkCount++; const connected = root.active && root.active.ssid === root.pendingConnection.ssid; - + if (connected) { connectionCheckTimer.stop(); immediateCheckTimer.stop(); immediateCheckTimer.checkCount = 0; if (root.pendingConnection.callback) { - root.pendingConnection.callback({ success: true, output: "Connected", error: "", exitCode: 0 }); + root.pendingConnection.callback({ + success: true, + output: "Connected", + error: "", + exitCode: 0 + }); } root.pendingConnection = null; } else { @@ -1018,9 +1060,9 @@ Singleton { if (proc && proc.stderr && proc.stderr.text) { const error = proc.stderr.text.trim(); if (error && error.length > 0) { - if (isConnectionCommand(proc.command)) { - const needsPassword = detectPasswordRequired(error); - + if (root.isConnectionCommand(proc.command)) { + const needsPassword = root.detectPasswordRequired(error); + if (needsPassword && !proc.callbackCalled && root.pendingConnection && root.pendingConnection.callback) { connectionCheckTimer.stop(); immediateCheckTimer.stop(); @@ -1047,7 +1089,7 @@ Singleton { } } } - + if (checkCount >= 6) { immediateCheckTimer.stop(); immediateCheckTimer.checkCount = 0; @@ -1069,7 +1111,12 @@ Singleton { immediateCheckTimer.stop(); immediateCheckTimer.checkCount = 0; if (root.pendingConnection.callback) { - root.pendingConnection.callback({ success: true, output: "Connected", error: "", exitCode: 0 }); + root.pendingConnection.callback({ + success: true, + output: "Connected", + error: "", + exitCode: 0 + }); } root.pendingConnection = null; } else { @@ -1086,13 +1133,13 @@ Singleton { if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { return ""; } - + const mask = (0xffffffff << (32 - cidrNum)) >>> 0; const octet1 = (mask >>> 24) & 0xff; const octet2 = (mask >>> 16) & 0xff; const octet3 = (mask >>> 8) & 0xff; const octet4 = mask & 0xff; - + return `${octet1}.${octet2}.${octet3}.${octet4}`; } @@ -1104,21 +1151,24 @@ Singleton { if (activeInterface && activeInterface.device) { interfaceName = activeInterface.device; } else { - if (callback) callback(null); + if (callback) + callback(null); return; } } - - executeCommand(["device", "show", interfaceName], (result) => { + + executeCommand(["device", "show", interfaceName], result => { if (!result.success || !result.output) { root.wirelessDeviceDetails = null; - if (callback) callback(null); + if (callback) + callback(null); return; } - + const details = parseDeviceDetails(result.output, false); root.wirelessDeviceDetails = details; - if (callback) callback(details); + if (callback) + callback(details); }); } @@ -1130,21 +1180,24 @@ Singleton { if (activeInterface && activeInterface.device) { interfaceName = activeInterface.device; } else { - if (callback) callback(null); + if (callback) + callback(null); return; } } - - executeCommand(["device", "show", interfaceName], (result) => { + + executeCommand(["device", "show", interfaceName], result => { if (!result.success || !result.output) { root.ethernetDeviceDetails = null; - if (callback) callback(null); + if (callback) + callback(null); return; } - + const details = parseDeviceDetails(result.output, true); root.ethernetDeviceDetails = details; - if (callback) callback(details); + if (callback) + callback(details); }); } @@ -1157,20 +1210,20 @@ Singleton { macAddress: "", speed: "" }; - + if (!output || output.length === 0) { return details; } - + const lines = output.trim().split("\n"); - + for (let i = 0; i < lines.length; i++) { const line = lines[i]; const parts = line.split(":"); if (parts.length >= 2) { const key = parts[0].trim(); const value = parts.slice(1).join(":").trim(); - + if (key.startsWith("IP4.ADDRESS")) { const ipParts = value.split("/"); details.ipAddress = ipParts[0] || ""; @@ -1196,46 +1249,36 @@ Singleton { } } } - + return details; } Process { id: rescanProc + command: ["nmcli", "dev", root.nmcliCommandWifi, "list", "--rescan", "yes"] - onExited: { - getNetworks(() => {}); - } + onExited: root.getNetworks() } Process { id: monitorProc + running: true command: ["nmcli", "monitor"] environment: ({ - LANG: "C.UTF-8", - LC_ALL: "C.UTF-8" - }) - + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) stdout: SplitParser { - onRead: { - log("Connection state change detected, refreshing..."); - root.refreshOnConnectionChange(); - } - } - - onExited: { - log("Monitor process exited, restarting..."); - Qt.callLater(() => { - monitorProc.running = true; - }, 2000); + onRead: root.refreshOnConnectionChange() } + onExited: Qt.callLater(() => monitorProc.running = true, 2000) } function refreshOnConnectionChange(): void { - getNetworks((networks) => { + getNetworks(networks => { const newActive = root.active; - + if (newActive && newActive.active) { Qt.callLater(() => { if (root.wirelessInterfaces.length > 0) { @@ -1246,7 +1289,7 @@ Singleton { getWirelessDeviceDetails(activeWireless.device, () => {}); } } - + if (root.ethernetInterfaces.length > 0) { const activeEthernet = root.ethernetInterfaces.find(iface => { return isConnectedState(iface.state); @@ -1260,7 +1303,7 @@ Singleton { root.wirelessDeviceDetails = null; root.ethernetDeviceDetails = null; } - + getWirelessInterfaces(() => {}); getEthernetInterfaces(() => { if (root.activeEthernet && root.activeEthernet.connected) { @@ -1277,7 +1320,7 @@ Singleton { getNetworks(() => {}); loadSavedConnections(() => {}); getEthernetInterfaces(() => {}); - + Qt.callLater(() => { if (root.wirelessInterfaces.length > 0) { const activeWireless = root.wirelessInterfaces.find(iface => { @@ -1287,7 +1330,7 @@ Singleton { getWirelessDeviceDetails(activeWireless.device, () => {}); } } - + if (root.ethernetInterfaces.length > 0) { const activeEthernet = root.ethernetInterfaces.find(iface => { return isConnectedState(iface.state); @@ -1299,4 +1342,3 @@ Singleton { }, 2000); } } - |