nmcli: fix errors + disable most logs

This commit is contained in:
2 * r + 2 * t 2025-11-15 15:53:30 +11:00
parent d123dc0b7e
commit 9825ad4d31

View file

@ -1,4 +1,5 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
@ -30,7 +31,6 @@ Singleton {
readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null
property list<var> activeProcesses: [] property list<var> activeProcesses: []
property var debugLogger: null
// Constants // Constants
readonly property string deviceTypeWifi: "wifi" readonly property string deviceTypeWifi: "wifi"
@ -55,37 +55,12 @@ Singleton {
readonly property string connectionParamPassword: "password" readonly property string connectionParamPassword: "password"
readonly property string connectionParamBssid: "802-11-wireless.bssid" 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 { function detectPasswordRequired(error: string): bool {
if (!error || error.length === 0) { if (!error || error.length === 0) {
return false; return false;
} }
return (error.includes("Secrets were required") || 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");
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> { function parseNetworkOutput(output: string): list<var> {
@ -97,20 +72,17 @@ Singleton {
const rep = new RegExp("\\\\:", "g"); const rep = new RegExp("\\\\:", "g");
const rep2 = new RegExp(PLACEHOLDER, "g"); const rep2 = new RegExp(PLACEHOLDER, "g");
const allNetworks = output.trim().split("\n") const allNetworks = output.trim().split("\n").filter(line => line && line.length > 0).map(n => {
.filter(line => line && line.length > 0) const net = n.replace(rep, PLACEHOLDER).split(":");
.map(n => { return {
const net = n.replace(rep, PLACEHOLDER).split(":"); active: net[0] === "yes",
return { strength: parseInt(net[1] || "0", 10) || 0,
active: net[0] === "yes", frequency: parseInt(net[2] || "0", 10) || 0,
strength: parseInt(net[1] || "0", 10) || 0, ssid: (net[3]?.replace(rep2, ":") ?? "").trim(),
frequency: parseInt(net[2] || "0", 10) || 0, bssid: (net[4]?.replace(rep2, ":") ?? "").trim(),
ssid: (net[3]?.replace(rep2, ":") ?? "").trim(), security: (net[5] ?? "").trim()
bssid: (net[4]?.replace(rep2, ":") ?? "").trim(), };
security: (net[5] ?? "").trim() }).filter(n => n.ssid && n.ssid.length > 0);
};
})
.filter(n => n.ssid && n.ssid.length > 0);
return allNetworks; return allNetworks;
} }
@ -188,9 +160,7 @@ Singleton {
return false; return false;
} }
return state === "100 (connected)" || return state === "100 (connected)" || state === "connected" || state.startsWith("connected");
state === "connected" ||
state.startsWith("connected");
} }
function executeCommand(args: list<string>, callback: var): void { function executeCommand(args: list<string>, callback: var): void {
@ -213,21 +183,23 @@ Singleton {
} }
function getDeviceStatus(callback: var): void { function getDeviceStatus(callback: var): void {
executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], (result) => { executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => {
if (callback) callback(result.output); if (callback)
callback(result.output);
}); });
} }
function getWirelessInterfaces(callback: var): void { 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); const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeWifi);
root.wirelessInterfaces = interfaces; root.wirelessInterfaces = interfaces;
if (callback) callback(interfaces); if (callback)
callback(interfaces);
}); });
} }
function getEthernetInterfaces(callback: var): void { 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 interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeEthernet);
const devices = []; const devices = [];
@ -251,13 +223,14 @@ Singleton {
root.ethernetInterfaces = interfaces; root.ethernetInterfaces = interfaces;
root.ethernetDevices = devices; root.ethernetDevices = devices;
if (callback) callback(interfaces); if (callback)
callback(interfaces);
}); });
} }
function connectEthernet(connectionName: string, interfaceName: string, callback: var): void { function connectEthernet(connectionName: string, interfaceName: string, callback: var): void {
if (connectionName && connectionName.length > 0) { if (connectionName && connectionName.length > 0) {
executeCommand([root.nmcliCommandConnection, "up", connectionName], (result) => { executeCommand([root.nmcliCommandConnection, "up", connectionName], result => {
if (result.success) { if (result.success) {
Qt.callLater(() => { Qt.callLater(() => {
getEthernetInterfaces(() => {}); getEthernetInterfaces(() => {});
@ -268,10 +241,11 @@ Singleton {
} }
}, 500); }, 500);
} }
if (callback) callback(result); if (callback)
callback(result);
}); });
} else if (interfaceName && interfaceName.length > 0) { } else if (interfaceName && interfaceName.length > 0) {
executeCommand([root.nmcliCommandDevice, "connect", interfaceName], (result) => { executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => {
if (result.success) { if (result.success) {
Qt.callLater(() => { Qt.callLater(() => {
getEthernetInterfaces(() => {}); getEthernetInterfaces(() => {});
@ -280,62 +254,94 @@ Singleton {
}, 1000); }, 1000);
}, 500); }, 500);
} }
if (callback) callback(result); if (callback)
callback(result);
}); });
} else { } 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 { function disconnectEthernet(connectionName: string, callback: var): void {
if (!connectionName || connectionName.length === 0) { 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; return;
} }
executeCommand([root.nmcliCommandConnection, "down", connectionName], (result) => { executeCommand([root.nmcliCommandConnection, "down", connectionName], result => {
if (result.success) { if (result.success) {
root.ethernetDeviceDetails = null; root.ethernetDeviceDetails = null;
Qt.callLater(() => { Qt.callLater(() => {
getEthernetInterfaces(() => {}); getEthernetInterfaces(() => {});
}, 500); }, 500);
} }
if (callback) callback(result); if (callback)
callback(result);
}); });
} }
function getAllInterfaces(callback: var): void { 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"); const interfaces = parseDeviceStatusOutput(result.output, "both");
if (callback) callback(interfaces); if (callback)
callback(interfaces);
}); });
} }
function isInterfaceConnected(interfaceName: string, callback: var): void { function isInterfaceConnected(interfaceName: string, callback: var): void {
executeCommand([root.nmcliCommandDevice, "status"], (result) => { executeCommand([root.nmcliCommandDevice, "status"], result => {
const lines = result.output.trim().split("\n"); const lines = result.output.trim().split("\n");
for (const line of lines) { for (const line of lines) {
const parts = line.split(/\s+/); const parts = line.split(/\s+/);
if (parts.length >= 3 && parts[0] === interfaceName) { if (parts.length >= 3 && parts[0] === interfaceName) {
const connected = isConnectedState(parts[2]); const connected = isConnectedState(parts[2]);
if (callback) callback(connected); if (callback)
callback(connected);
return; return;
} }
} }
if (callback) callback(false); if (callback)
callback(false);
}); });
} }
function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void { function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void {
if (isSecure) { if (isSecure) {
const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0;
connectWireless(ssid, "", bssid, (result) => { connectWireless(ssid, "", bssid, result => {
if (result.success) { 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) { } 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 { } else {
if (callback) callback(result); if (callback)
callback(result);
} }
}); });
} else { } else {
@ -353,7 +359,12 @@ Singleton {
const maxRetries = 2; const maxRetries = 2;
if (callback) { 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(); connectionCheckTimer.start();
immediateCheckTimer.checkCount = 0; immediateCheckTimer.checkCount = 0;
immediateCheckTimer.start(); immediateCheckTimer.start();
@ -369,54 +380,45 @@ Singleton {
if (password && password.length > 0) { if (password && password.length > 0) {
cmd.push(root.connectionParamPassword, password); cmd.push(root.connectionParamPassword, password);
} }
executeCommand(cmd, (result) => { executeCommand(cmd, result => {
if (result.needsPassword && callback) { if (result.needsPassword && callback) {
if (callback) callback(result); if (callback)
callback(result);
return; return;
} }
if (!result.success && root.pendingConnection && retries < maxRetries) { 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(() => { Qt.callLater(() => {
connectWireless(ssid, password, bssid, callback, retries + 1); connectWireless(ssid, password, bssid, callback, retries + 1);
}, 1000); }, 1000);
} else if (!result.success && root.pendingConnection) { } else if (!result.success && root.pendingConnection) {} else if (result.success && callback) {} else if (!result.success && !root.pendingConnection) {
} else if (result.success && callback) { if (callback)
} else if (!result.success && !root.pendingConnection) { callback(result);
if (callback) callback(result);
} }
}); });
} }
function createConnectionWithPassword(ssid: string, bssidUpper: string, password: string, callback: var): void { function createConnectionWithPassword(ssid: string, bssidUpper: string, password: string, callback: var): void {
checkAndDeleteConnection(ssid, () => { checkAndDeleteConnection(ssid, () => {
const cmd = [root.nmcliCommandConnection, "add", 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];
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) => { executeCommand(cmd, result => {
if (result.success) { if (result.success) {
loadSavedConnections(() => {}); loadSavedConnections(() => {});
activateConnection(ssid, callback); activateConnection(ssid, callback);
} else { } else {
const hasDuplicateWarning = result.error && ( const hasDuplicateWarning = result.error && (result.error.includes("another connection with the name") || result.error.includes("Reference the connection by its uuid"));
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)) { if (hasDuplicateWarning || (result.exitCode > 0 && result.exitCode < 10)) {
loadSavedConnections(() => {}); loadSavedConnections(() => {});
activateConnection(ssid, callback); activateConnection(ssid, callback);
} else { } 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]; let fallbackCmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid, root.connectionParamPassword, password];
executeCommand(fallbackCmd, (fallbackResult) => { executeCommand(fallbackCmd, fallbackResult => {
if (callback) callback(fallbackResult); if (callback)
callback(fallbackResult);
}); });
} }
} }
@ -425,31 +427,35 @@ Singleton {
} }
function checkAndDeleteConnection(ssid: string, callback: var): void { function checkAndDeleteConnection(ssid: string, callback: var): void {
executeCommand([root.nmcliCommandConnection, "show", ssid], (result) => { executeCommand([root.nmcliCommandConnection, "show", ssid], result => {
if (result.success) { if (result.success) {
executeCommand([root.nmcliCommandConnection, "delete", ssid], (deleteResult) => { executeCommand([root.nmcliCommandConnection, "delete", ssid], deleteResult => {
Qt.callLater(() => { Qt.callLater(() => {
if (callback) callback(); if (callback)
callback();
}, 300); }, 300);
}); });
} else { } else {
if (callback) callback(); if (callback)
callback();
} }
}); });
} }
function activateConnection(connectionName: string, callback: var): void { function activateConnection(connectionName: string, callback: var): void {
executeCommand([root.nmcliCommandConnection, "up", connectionName], (result) => { executeCommand([root.nmcliCommandConnection, "up", connectionName], result => {
if (callback) callback(result); if (callback)
callback(result);
}); });
} }
function loadSavedConnections(callback: var): void { 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) { if (!result.success) {
root.savedConnections = []; root.savedConnections = [];
root.savedConnectionSsids = []; root.savedConnectionSsids = [];
if (callback) callback([]); if (callback)
callback([]);
return; return;
} }
@ -485,7 +491,8 @@ Singleton {
} else { } else {
root.savedConnectionSsids = []; root.savedConnectionSsids = [];
root.wifiConnectionQueue = []; root.wifiConnectionQueue = [];
if (callback) callback(root.savedConnectionSsids); if (callback)
callback(root.savedConnectionSsids);
} }
} }
@ -494,7 +501,7 @@ Singleton {
const connectionName = root.wifiConnectionQueue[root.currentSsidQueryIndex]; const connectionName = root.wifiConnectionQueue[root.currentSsidQueryIndex];
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) { if (result.success) {
processSsidOutput(result.output); processSsidOutput(result.output);
} }
@ -503,7 +510,8 @@ Singleton {
} else { } else {
root.wifiConnectionQueue = []; root.wifiConnectionQueue = [];
root.currentSsidQueryIndex = 0; root.currentSsidQueryIndex = 0;
if (callback) callback(root.savedConnectionSsids); if (callback)
callback(root.savedConnectionSsids);
} }
} }
@ -538,62 +546,65 @@ Singleton {
} }
} }
const hasSsid = root.savedConnectionSsids.some(savedSsid => const hasSsid = root.savedConnectionSsids.some(savedSsid => savedSsid && savedSsid.toLowerCase().trim() === ssidLower);
savedSsid && savedSsid.toLowerCase().trim() === ssidLower
);
if (hasSsid) { if (hasSsid) {
return true; return true;
} }
const hasConnectionName = root.savedConnections.some(connName => const hasConnectionName = root.savedConnections.some(connName => connName && connName.toLowerCase().trim() === ssidLower);
connName && connName.toLowerCase().trim() === ssidLower
);
return hasConnectionName; return hasConnectionName;
} }
function forgetNetwork(ssid: string, callback: var): void { function forgetNetwork(ssid: string, callback: var): void {
if (!ssid || ssid.length === 0) { 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; return;
} }
const connectionName = root.savedConnections.find(conn => const connectionName = root.savedConnections.find(conn => conn && conn.toLowerCase().trim() === ssid.toLowerCase().trim()) || ssid;
conn && conn.toLowerCase().trim() === ssid.toLowerCase().trim()
) || ssid;
executeCommand([root.nmcliCommandConnection, "delete", connectionName], (result) => { executeCommand([root.nmcliCommandConnection, "delete", connectionName], result => {
if (result.success) { if (result.success) {
Qt.callLater(() => { Qt.callLater(() => {
loadSavedConnections(() => {}); loadSavedConnections(() => {});
}, 500); }, 500);
} }
if (callback) callback(result); if (callback)
callback(result);
}); });
} }
function disconnect(interfaceName: string, callback: var): void { function disconnect(interfaceName: string, callback: var): void {
if (interfaceName && interfaceName.length > 0) { if (interfaceName && interfaceName.length > 0) {
executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], (result) => { executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => {
if (callback) callback(result.success ? result.output : ""); if (callback)
callback(result.success ? result.output : "");
}); });
} else { } else {
executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], (result) => { executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => {
if (callback) callback(result.success ? result.output : ""); if (callback)
callback(result.success ? result.output : "");
}); });
} }
} }
function disconnectFromNetwork(): void { function disconnectFromNetwork(): void {
if (active && active.ssid) { if (active && active.ssid) {
executeCommand([root.nmcliCommandConnection, "down", active.ssid], (result) => { executeCommand([root.nmcliCommandConnection, "down", active.ssid], result => {
if (result.success) { if (result.success) {
getNetworks(() => {}); getNetworks(() => {});
} }
}); });
} else { } else {
executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], (result) => { executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => {
if (result.success) { if (result.success) {
getNetworks(() => {}); getNetworks(() => {});
} }
@ -602,13 +613,14 @@ Singleton {
} }
function getDeviceDetails(interfaceName: string, callback: var): void { function getDeviceDetails(interfaceName: string, callback: var): void {
executeCommand([root.nmcliCommandDevice, "show", interfaceName], (result) => { executeCommand([root.nmcliCommandDevice, "show", interfaceName], result => {
if (callback) callback(result.output); if (callback)
callback(result.output);
}); });
} }
function refreshStatus(callback: var): void { function refreshStatus(callback: var): void {
getDeviceStatus((output) => { getDeviceStatus(output => {
const lines = output.trim().split("\n"); const lines = output.trim().split("\n");
let connected = false; let connected = false;
let activeIf = ""; let activeIf = "";
@ -631,31 +643,48 @@ Singleton {
root.activeInterface = activeIf; root.activeInterface = activeIf;
root.activeConnection = activeConn; 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 { function bringInterfaceUp(interfaceName: string, callback: var): void {
if (interfaceName && interfaceName.length > 0) { if (interfaceName && interfaceName.length > 0) {
executeCommand([root.nmcliCommandDevice, "connect", interfaceName], (result) => { executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => {
if (callback) { if (callback) {
callback(result); callback(result);
} }
}); });
} else { } 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 { function bringInterfaceDown(interfaceName: string, callback: var): void {
if (interfaceName && interfaceName.length > 0) { if (interfaceName && interfaceName.length > 0) {
executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], (result) => { executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => {
if (callback) { if (callback) {
callback(result); callback(result);
} }
}); });
} else { } 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) { if (interfaceName && interfaceName.length > 0) {
cmd.push(root.connectionParamIfname, interfaceName); cmd.push(root.connectionParamIfname, interfaceName);
} }
executeCommand(cmd, (result) => { executeCommand(cmd, result => {
if (callback) { if (callback) {
callback(result); callback(result);
} }
@ -677,14 +706,16 @@ Singleton {
function enableWifi(enabled: bool, callback: var): void { function enableWifi(enabled: bool, callback: var): void {
const cmd = enabled ? "on" : "off"; const cmd = enabled ? "on" : "off";
executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi, cmd], (result) => { executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi, cmd], result => {
if (result.success) { if (result.success) {
getWifiStatus((status) => { getWifiStatus(status => {
root.wifiEnabled = status; root.wifiEnabled = status;
if (callback) callback(result); if (callback)
callback(result);
}); });
} else { } else {
if (callback) callback(result); if (callback)
callback(result);
} }
}); });
} }
@ -695,21 +726,24 @@ Singleton {
} }
function getWifiStatus(callback: var): void { function getWifiStatus(callback: var): void {
executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi], (result) => { executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi], result => {
if (result.success) { if (result.success) {
const enabled = result.output.trim() === "enabled"; const enabled = result.output.trim() === "enabled";
root.wifiEnabled = enabled; root.wifiEnabled = enabled;
if (callback) callback(enabled); if (callback)
callback(enabled);
} else { } else {
if (callback) callback(root.wifiEnabled); if (callback)
callback(root.wifiEnabled);
} }
}); });
} }
function getNetworks(callback: var): void { function getNetworks(callback: var): void {
executeCommand(["-g", root.networkDetailFields, "d", "w"], (result) => { executeCommand(["-g", root.networkDetailFields, "d", "w"], result => {
if (!result.success) { if (!result.success) {
if (callback) callback([]); if (callback)
callback([]);
return; return;
} }
@ -717,11 +751,7 @@ Singleton {
const networks = deduplicateNetworks(allNetworks); const networks = deduplicateNetworks(allNetworks);
const rNetworks = root.networks; const rNetworks = root.networks;
const destroyed = rNetworks.filter(rn => !networks.find(n => const destroyed = rNetworks.filter(rn => !networks.find(n => n.frequency === rn.frequency && n.ssid === rn.ssid && n.bssid === rn.bssid));
n.frequency === rn.frequency &&
n.ssid === rn.ssid &&
n.bssid === rn.bssid
));
for (const network of destroyed) { for (const network of destroyed) {
const index = rNetworks.indexOf(network); const index = rNetworks.indexOf(network);
if (index >= 0) { if (index >= 0) {
@ -731,11 +761,7 @@ Singleton {
} }
for (const network of networks) { for (const network of networks) {
const match = rNetworks.find(n => const match = rNetworks.find(n => n.frequency === network.frequency && n.ssid === network.ssid && n.bssid === network.bssid);
n.frequency === network.frequency &&
n.ssid === network.ssid &&
n.bssid === network.bssid
);
if (match) { if (match) {
match.lastIpcObject = network; match.lastIpcObject = network;
} else { } else {
@ -745,7 +771,8 @@ Singleton {
} }
} }
if (callback) callback(root.networks); if (callback)
callback(root.networks);
checkPendingConnection(); checkPendingConnection();
}); });
} }
@ -755,9 +782,10 @@ Singleton {
if (interfaceName && interfaceName.length > 0) { if (interfaceName && interfaceName.length > 0) {
cmd.push(root.connectionParamIfname, interfaceName); cmd.push(root.connectionParamIfname, interfaceName);
} }
executeCommand(cmd, (result) => { executeCommand(cmd, result => {
if (!result.success) { if (!result.success) {
if (callback) callback([]); if (callback)
callback([]);
return; return;
} }
@ -766,7 +794,8 @@ Singleton {
const seenSSIDs = new Set(); const seenSSIDs = new Set();
for (const line of lines) { for (const line of lines) {
if (!line || line.length === 0) continue; if (!line || line.length === 0)
continue;
const parts = line.split(":"); const parts = line.split(":");
if (parts.length >= 1) { if (parts.length >= 1) {
@ -790,7 +819,8 @@ Singleton {
return b.signalValue - a.signalValue; return b.signalValue - a.signalValue;
}); });
if (callback) callback(ssids); if (callback)
callback(ssids);
}); });
} }
@ -833,71 +863,73 @@ Singleton {
component CommandProcess: Process { component CommandProcess: Process {
id: proc id: proc
property var callback: null property var callback: null
property list<string> command: [] property list<string> command: []
property bool callbackCalled: false property bool callbackCalled: false
property int exitCode: 0 property int exitCode: 0
signal processFinished signal processFinished
environment: ({ environment: ({
LANG: "C.UTF-8", LANG: "C.UTF-8",
LC_ALL: "C.UTF-8" LC_ALL: "C.UTF-8"
}) })
stdout: StdioCollector { stdout: StdioCollector {
id: stdoutCollector id: stdoutCollector
onStreamFinished: {
}
} }
stderr: StdioCollector { stderr: StdioCollector {
id: stderrCollector id: stderrCollector
onStreamFinished: { onStreamFinished: {
const error = text.trim(); const error = text.trim();
if (error && error.length > 0) { if (error && error.length > 0) {
const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : "";
handlePasswordRequired(proc, error, output, -1); root.handlePasswordRequired(proc, error, output, -1);
} }
} }
} }
onExited: { onExited: code => {
proc.exitCode = exitCode; exitCode = code;
Qt.callLater(() => { Qt.callLater(() => {
if (proc.callbackCalled) { if (callbackCalled) {
proc.processFinished(); processFinished();
return; return;
} }
if (proc.callback) { if (proc.callback) {
const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : "";
const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : ""; const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : "";
const success = proc.exitCode === 0; const success = exitCode === 0;
const cmdIsConnection = isConnectionCommand(proc.command); const cmdIsConnection = isConnectionCommand(proc.command);
if (handlePasswordRequired(proc, error, output, proc.exitCode)) { if (root.handlePasswordRequired(proc, error, output, exitCode)) {
proc.processFinished(); processFinished();
return; return;
} }
const needsPassword = cmdIsConnection && detectPasswordRequired(error); const needsPassword = cmdIsConnection && root.detectPasswordRequired(error);
if (!success && cmdIsConnection && root.pendingConnection) { if (!success && cmdIsConnection && root.pendingConnection) {
const failedSsid = root.pendingConnection.ssid; const failedSsid = root.pendingConnection.ssid;
root.connectionFailed(failedSsid); root.connectionFailed(failedSsid);
} }
proc.callbackCalled = true; callbackCalled = true;
proc.callback({ callback({
success: success, success: success,
output: output, output: output,
error: error, error: error,
exitCode: proc.exitCode, exitCode: proc.exitCode,
needsPassword: needsPassword || false needsPassword: needsPassword || false
}); });
proc.processFinished(); processFinished();
} else { } else {
proc.processFinished(); processFinished();
} }
}); });
} }
@ -905,6 +937,7 @@ Singleton {
Component { Component {
id: commandProc id: commandProc
CommandProcess {} CommandProcess {}
} }
@ -921,11 +954,13 @@ Singleton {
Component { Component {
id: apComp id: apComp
AccessPoint {} AccessPoint {}
} }
Timer { Timer {
id: connectionCheckTimer id: connectionCheckTimer
interval: 4000 interval: 4000
onTriggered: { onTriggered: {
if (root.pendingConnection) { if (root.pendingConnection) {
@ -938,8 +973,8 @@ Singleton {
if (proc && proc.stderr && proc.stderr.text) { if (proc && proc.stderr && proc.stderr.text) {
const error = proc.stderr.text.trim(); const error = proc.stderr.text.trim();
if (error && error.length > 0) { if (error && error.length > 0) {
if (isConnectionCommand(proc.command)) { if (root.isConnectionCommand(proc.command)) {
const needsPassword = detectPasswordRequired(error); const needsPassword = root.detectPasswordRequired(error);
if (needsPassword && !proc.callbackCalled && root.pendingConnection) { if (needsPassword && !proc.callbackCalled && root.pendingConnection) {
const pending = root.pendingConnection; const pending = root.pendingConnection;
@ -994,10 +1029,12 @@ Singleton {
Timer { Timer {
id: immediateCheckTimer id: immediateCheckTimer
property int checkCount: 0
interval: 500 interval: 500
repeat: true repeat: true
triggeredOnStart: false triggeredOnStart: false
property int checkCount: 0
onTriggered: { onTriggered: {
if (root.pendingConnection) { if (root.pendingConnection) {
@ -1009,7 +1046,12 @@ Singleton {
immediateCheckTimer.stop(); immediateCheckTimer.stop();
immediateCheckTimer.checkCount = 0; immediateCheckTimer.checkCount = 0;
if (root.pendingConnection.callback) { 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; root.pendingConnection = null;
} else { } else {
@ -1018,8 +1060,8 @@ Singleton {
if (proc && proc.stderr && proc.stderr.text) { if (proc && proc.stderr && proc.stderr.text) {
const error = proc.stderr.text.trim(); const error = proc.stderr.text.trim();
if (error && error.length > 0) { if (error && error.length > 0) {
if (isConnectionCommand(proc.command)) { if (root.isConnectionCommand(proc.command)) {
const needsPassword = detectPasswordRequired(error); const needsPassword = root.detectPasswordRequired(error);
if (needsPassword && !proc.callbackCalled && root.pendingConnection && root.pendingConnection.callback) { if (needsPassword && !proc.callbackCalled && root.pendingConnection && root.pendingConnection.callback) {
connectionCheckTimer.stop(); connectionCheckTimer.stop();
@ -1069,7 +1111,12 @@ Singleton {
immediateCheckTimer.stop(); immediateCheckTimer.stop();
immediateCheckTimer.checkCount = 0; immediateCheckTimer.checkCount = 0;
if (root.pendingConnection.callback) { 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; root.pendingConnection = null;
} else { } else {
@ -1104,21 +1151,24 @@ Singleton {
if (activeInterface && activeInterface.device) { if (activeInterface && activeInterface.device) {
interfaceName = activeInterface.device; interfaceName = activeInterface.device;
} else { } else {
if (callback) callback(null); if (callback)
callback(null);
return; return;
} }
} }
executeCommand(["device", "show", interfaceName], (result) => { executeCommand(["device", "show", interfaceName], result => {
if (!result.success || !result.output) { if (!result.success || !result.output) {
root.wirelessDeviceDetails = null; root.wirelessDeviceDetails = null;
if (callback) callback(null); if (callback)
callback(null);
return; return;
} }
const details = parseDeviceDetails(result.output, false); const details = parseDeviceDetails(result.output, false);
root.wirelessDeviceDetails = details; root.wirelessDeviceDetails = details;
if (callback) callback(details); if (callback)
callback(details);
}); });
} }
@ -1130,21 +1180,24 @@ Singleton {
if (activeInterface && activeInterface.device) { if (activeInterface && activeInterface.device) {
interfaceName = activeInterface.device; interfaceName = activeInterface.device;
} else { } else {
if (callback) callback(null); if (callback)
callback(null);
return; return;
} }
} }
executeCommand(["device", "show", interfaceName], (result) => { executeCommand(["device", "show", interfaceName], result => {
if (!result.success || !result.output) { if (!result.success || !result.output) {
root.ethernetDeviceDetails = null; root.ethernetDeviceDetails = null;
if (callback) callback(null); if (callback)
callback(null);
return; return;
} }
const details = parseDeviceDetails(result.output, true); const details = parseDeviceDetails(result.output, true);
root.ethernetDeviceDetails = details; root.ethernetDeviceDetails = details;
if (callback) callback(details); if (callback)
callback(details);
}); });
} }
@ -1202,38 +1255,28 @@ Singleton {
Process { Process {
id: rescanProc id: rescanProc
command: ["nmcli", "dev", root.nmcliCommandWifi, "list", "--rescan", "yes"] command: ["nmcli", "dev", root.nmcliCommandWifi, "list", "--rescan", "yes"]
onExited: { onExited: root.getNetworks()
getNetworks(() => {});
}
} }
Process { Process {
id: monitorProc id: monitorProc
running: true running: true
command: ["nmcli", "monitor"] command: ["nmcli", "monitor"]
environment: ({ environment: ({
LANG: "C.UTF-8", LANG: "C.UTF-8",
LC_ALL: "C.UTF-8" LC_ALL: "C.UTF-8"
}) })
stdout: SplitParser { stdout: SplitParser {
onRead: { onRead: root.refreshOnConnectionChange()
log("Connection state change detected, refreshing...");
root.refreshOnConnectionChange();
}
}
onExited: {
log("Monitor process exited, restarting...");
Qt.callLater(() => {
monitorProc.running = true;
}, 2000);
} }
onExited: Qt.callLater(() => monitorProc.running = true, 2000)
} }
function refreshOnConnectionChange(): void { function refreshOnConnectionChange(): void {
getNetworks((networks) => { getNetworks(networks => {
const newActive = root.active; const newActive = root.active;
if (newActive && newActive.active) { if (newActive && newActive.active) {
@ -1299,4 +1342,3 @@ Singleton {
}, 2000); }, 2000);
} }
} }