Compare commits

...

1 Commits

Author SHA1 Message Date
Copilot
b5feb888d2 Fix incorrect character encoding over Telnet and Serial connections (#196)
Some checks failed
build-packages / build-macos-latest (push) Has been cancelled
build-packages / build-ubuntu-latest (push) Has been cancelled
build-packages / build-windows-latest (push) Has been cancelled
build-packages / release (push) Has been cancelled
* Initial plan

* fix: use UTF-8 encoding for Telnet and Serial data instead of binary (latin1)

Fixes incorrect character encoding where accented characters (e.g. ç, ã, é)
were displayed as garbled text (e.g. ç, ã, é) over Telnet connections.

The root cause was Buffer.toString('binary') which uses latin1 encoding,
corrupting multi-byte UTF-8 sequences. Changed to toString('utf8') for both
Telnet and Serial data handlers.

Co-authored-by: binaricat <16399091+binaricat@users.noreply.github.com>

* fix: use streaming StringDecoder for UTF-8 decoding in Telnet and Serial

Buffer.toString('utf8') on individual chunks loses multibyte characters
when a UTF-8 sequence is split across TCP/serial data events. Use
StringDecoder to carry incomplete trailing bytes into the next event.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: respect configured charset for Telnet and use latin1 for Serial

Telnet: use the user-configured charset (options.charset) to select the
StringDecoder encoding instead of hardcoding UTF-8, so non-UTF-8
endpoints (e.g. ISO-8859-1) decode correctly.

Serial: use latin1 (byte-preserving) instead of UTF-8 to avoid
corrupting 8-bit/binary serial traffic and legacy single-byte encodings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: binaricat <16399091+binaricat@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:05:05 +08:00

View File

@@ -7,6 +7,7 @@ const os = require("node:os");
const fs = require("node:fs");
const net = require("node:net");
const path = require("node:path");
const { StringDecoder } = require("node:string_decoder");
const pty = require("node-pty");
const { SerialPort } = require("serialport");
@@ -315,15 +316,30 @@ async function startTelnetSession(event, options) {
resolve({ sessionId });
});
const charsetToNodeEncoding = (charset) => {
if (!charset) return 'utf8';
const normalized = String(charset).trim().toLowerCase().replace(/[^a-z0-9]/g, '');
if (['utf8', 'utf-8'].includes(normalized)) return 'utf8';
if (['latin1', 'iso88591', 'iso-8859-1', 'binary'].includes(normalized)) return 'latin1';
if (normalized === 'ascii') return 'ascii';
if (['utf16le', 'ucs2'].includes(normalized)) return 'utf16le';
return 'utf8';
};
const telnetDecoder = new StringDecoder(charsetToNodeEncoding(options.charset));
socket.on('data', (data) => {
const session = sessions.get(sessionId);
if (!session) return;
const cleanData = handleTelnetNegotiation(data);
if (cleanData.length > 0) {
const contents = electronModule.webContents.fromId(session.webContentsId);
contents?.send("netcatty:data", { sessionId, data: cleanData.toString('binary') });
const decoded = telnetDecoder.write(cleanData);
if (decoded) {
const contents = electronModule.webContents.fromId(session.webContentsId);
contents?.send("netcatty:data", { sessionId, data: decoded });
}
}
});
@@ -513,9 +529,14 @@ async function startSerialSession(event, options) {
};
sessions.set(sessionId, session);
const serialDecoder = new StringDecoder('latin1');
serialPort.on('data', (data) => {
const contents = electronModule.webContents.fromId(session.webContentsId);
contents?.send("netcatty:data", { sessionId, data: data.toString('binary') });
const decoded = serialDecoder.write(data);
if (decoded) {
const contents = electronModule.webContents.fromId(session.webContentsId);
contents?.send("netcatty:data", { sessionId, data: decoded });
}
});
serialPort.on('error', (err) => {