diff --git a/ui/commands/common.js b/ui/commands/common.js index ca55bff..3f7d715 100644 --- a/ui/commands/common.js +++ b/ui/commands/common.js @@ -17,6 +17,49 @@ import Exception from "./exception.js"; +export const charsetPresets = [ + "utf-8", + "ibm866", + "iso-8859-2", + "iso-8859-3", + "iso-8859-4", + "iso-8859-5", + "iso-8859-6", + "iso-8859-7", + "iso-8859-8", + "iso-8859-8i", + "iso-8859-10", + "iso-8859-13", + "iso-8859-14", + "iso-8859-15", + "iso-8859-16", + "koi8-r", + "koi8-u", + "macintosh", + "windows-874", + "windows-1250", + "windows-1251", + "windows-1252", + "windows-1253", + "windows-1254", + "windows-1255", + "windows-1256", + "windows-1257", + "windows-1258", + "x-mac-cyrillic", + "gbk", + "gb18030", + "hz-gb-2312", + "big5", + "euc-jp", + "iso-2022-jp", + "shift-jis", + "euc-kr", + "iso-2022-kr", + "utf-16be", + "utf-16le" +]; + const numCharators = { "0": true, "1": true, diff --git a/ui/commands/telnet.js b/ui/commands/telnet.js index 3159fd1..a2885ed 100644 --- a/ui/commands/telnet.js +++ b/ui/commands/telnet.js @@ -208,6 +208,24 @@ const initialFieldDef = { return "Look like " + addr.type + " address"; } + }, + Encoding: { + name: "Encoding", + description: "The character encoding of the server", + type: "select", + value: "utf-8", + example: common.charsetPresets.join(","), + verify(d) { + for (let i in common.charsetPresets) { + if (common.charsetPresets[i] !== d) { + continue; + } + + return ""; + } + + throw new Error('The character encoding "' + d + '" is not supported'); + } } }; @@ -288,7 +306,8 @@ class Wizard { let self = this; let parsedConfig = { - host: address.parseHostPort(configInput.host, DEFAULT_PORT) + host: address.parseHostPort(configInput.host, DEFAULT_PORT), + charset: configInput.charset }; return new Telnet(sender, parsedConfig, { @@ -319,6 +338,7 @@ class Wizard { configInput.host, self.info, self.controls.get("Telnet", { + charset: parsedConfig.charset, send(data) { return commandHandler.sendData(data); }, @@ -359,7 +379,14 @@ class Wizard { self.hasStarted = true; self.streams.request(COMMAND_ID, sd => { - return self.buildCommand(sd, this.config, this.session); + return self.buildCommand( + sd, + { + host: this.config.host, + charset: this.config.charset ? this.config.charset : "utf-8" + }, + this.session + ); }); return self.stepWaitForAcceptWait(); @@ -373,13 +400,20 @@ class Wizard { self.hasStarted = true; self.streams.request(COMMAND_ID, sd => { - return self.buildCommand(sd, r, this.session); + return self.buildCommand( + sd, + { + host: r.host, + charset: r.encoding + }, + this.session + ); }); self.step.resolve(self.stepWaitForAcceptWait()); }, () => {}, - command.fields(initialFieldDef, [{ name: "Host" }]) + command.fields(initialFieldDef, [{ name: "Host" }, { name: "Encoding" }]) ); } } @@ -408,18 +442,39 @@ export class Command { } launch(info, launcher, streams, subs, controls, history) { + const d = launcher.split("|", 2); + + if (d.length <= 0) { + throw new Exception('Given launcher "' + launcher + '" was invalid'); + } + try { - initialFieldDef["Host"].verify(launcher); + initialFieldDef["Host"].verify(d[0]); } catch (e) { throw new Exception( 'Given launcher "' + launcher + '" was invalid: ' + e ); } + let charset = "utf-8"; + + if (d.length > 1) { + try { + initialFieldDef["Encoding"].verify(d[1]); + + charset = d[1]; + } catch (e) { + throw new Exception( + 'Given launcher "' + launcher + '" was invalid: ' + e + ); + } + } + return this.builder( info, { - host: launcher + host: d[0], + charset: charset }, null, streams, @@ -430,6 +485,6 @@ export class Command { } launcher(config) { - return config.host; + return config.host + (config.charset ? "|" + config.charset : ""); } } diff --git a/ui/common.css b/ui/common.css index ec0ac2e..be67e29 100644 --- a/ui/common.css +++ b/ui/common.css @@ -356,7 +356,6 @@ body { display: block; width: 100%; overflow: auto; - padding: 1px; } .form1 > fieldset .field.horizontal { @@ -381,6 +380,7 @@ body { .form1 > fieldset .field, .form1 > fieldset .field input, +.form1 > fieldset .field select, .form1 > fieldset .field textarea, .form1 > fieldset .field button { vertical-align: middle; @@ -416,6 +416,7 @@ body { } .form1 > fieldset .field > input, +.form1 > fieldset .field > select, .form1 > fieldset .field > textarea, .form1 > fieldset .field > button { box-sizing: border-box; @@ -438,6 +439,7 @@ body { .form1 > fieldset .field > input[type="tel"], .form1 > fieldset .field > input[type="url"], .form1 > fieldset .field > input[type="password"], +.form1 > fieldset .field > select, .form1 > fieldset .field > textarea { width: 100%; padding: 10px; @@ -481,18 +483,21 @@ body { .form1 > fieldset .field.error > input[type="tel"], .form1 > fieldset .field.error > input[type="url"], .form1 > fieldset .field.error > input[type="password"], +.form1 > fieldset .field.error > select, .form1 > fieldset .field.error > textarea { background: #483535; border-bottom: 2px solid #a83333; } .form1 > fieldset .field > input:disabled, +.form1 > fieldset .field > select:disabled, .form1 > fieldset .field > textarea:disabled, .form1 > fieldset .field > button:disabled { opacity: 0.35; } .form1 > fieldset .field > input:disabled:active, +.form1 > fieldset .field > select:disabled:active, .form1 > fieldset .field > textarea:disabled:active, .form1 > fieldset .field > button:disabled:active { opacity: 0.5; @@ -516,6 +521,7 @@ body { .form1 > fieldset .field > input[type="tel"]:focus, .form1 > fieldset .field > input[type="url"]:focus, .form1 > fieldset .field > input[type="password"]:focus, +.form1 > fieldset .field > select:focus, .form1 > fieldset .field > textarea:focus { background: #222; border-bottom: 2px solid #e9a; diff --git a/ui/control/telnet.js b/ui/control/telnet.js index c1a7442..8ee1251 100644 --- a/ui/control/telnet.js +++ b/ui/control/telnet.js @@ -316,6 +316,23 @@ class Control { this.colorM = color; this.colors = this.colorM.get(); + if (!data.charset || data.charset === "utf-8") { + this.charsetDecoder = d => { + return d; + }; + } else { + let dec = new TextDecoder(data.charset), + enc = new TextEncoder(); + + this.charsetDecoder = d => { + return enc.encode( + dec.decode(d, { + stream: true + }) + ); + }; + } + this.sender = data.send; this.closer = data.close; this.closed = false; @@ -332,7 +349,7 @@ class Control { this.parser = new Parser( this.sender, d => { - self.subs.resolve(d); + self.subs.resolve(this.charsetDecoder(d)); }, { setEcho(newVal) { diff --git a/ui/widgets/connector.vue b/ui/widgets/connector.vue index b3e74d5..6cda1ce 100644 --- a/ui/widgets/connector.vue +++ b/ui/widgets/connector.vue @@ -153,6 +153,8 @@ autocomplete="off" :name="field.field.name" :value="option" + :checked="field.field.value === option" + :aria-checked="field.field.value === option" @input="verify(key, field, false)" @change="verify(key, field, true)" /> @@ -160,6 +162,27 @@ +
+ +
+
{{ field.error }}
{{ field.message }}