|
|
@@ -3,7 +3,7 @@ import colors from 'ansi-colors'
|
|
|
import stripAnsi from 'strip-ansi'
|
|
|
import { Injector } from '@angular/core'
|
|
|
import { Profile, LogService } from 'tabby-core'
|
|
|
-import { BaseSession, LoginScriptsOptions, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal'
|
|
|
+import { BaseSession, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal'
|
|
|
import { Subject, Observable } from 'rxjs'
|
|
|
|
|
|
|
|
|
@@ -41,6 +41,21 @@ enum TelnetOptions {
|
|
|
NEW_ENVIRON = 0x27,
|
|
|
}
|
|
|
|
|
|
+class UnescapeFFMiddleware extends SessionMiddleware {
|
|
|
+ feedFromSession (data: Buffer): void {
|
|
|
+ while (data.includes(0xff)) {
|
|
|
+ const pos = data.indexOf(0xff)
|
|
|
+
|
|
|
+ this.outputToTerminal.next(data.slice(0, pos))
|
|
|
+ this.outputToTerminal.next(Buffer.from([0xff, 0xff]))
|
|
|
+
|
|
|
+ data = data.slice(pos + 1)
|
|
|
+ }
|
|
|
+
|
|
|
+ this.outputToTerminal.next(data)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
export class TelnetSession extends BaseSession {
|
|
|
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
|
|
|
|
|
@@ -48,7 +63,6 @@ export class TelnetSession extends BaseSession {
|
|
|
private socket: Socket
|
|
|
private streamProcessor: TerminalStreamProcessor
|
|
|
private telnetProtocol = false
|
|
|
- private echoEnabled = false
|
|
|
private lastWidth = 0
|
|
|
private lastHeight = 0
|
|
|
private requestedOptions = new Set<number>()
|
|
|
@@ -59,33 +73,10 @@ export class TelnetSession extends BaseSession {
|
|
|
) {
|
|
|
super(injector.get(LogService).create(`telnet-${profile.options.host}-${profile.options.port}`))
|
|
|
this.streamProcessor = new TerminalStreamProcessor(profile.options)
|
|
|
- this.streamProcessor.outputToSession$.subscribe(data => {
|
|
|
- this.socket.write(this.unescapeFF(data))
|
|
|
- })
|
|
|
- this.streamProcessor.outputToTerminal$.subscribe(data => {
|
|
|
- this.emitOutput(data)
|
|
|
- })
|
|
|
+ this.middleware.push(this.streamProcessor)
|
|
|
this.setLoginScriptsOptions(profile.options)
|
|
|
}
|
|
|
|
|
|
- unescapeFF (data: Buffer): Buffer {
|
|
|
- if (!this.telnetProtocol) {
|
|
|
- return data
|
|
|
- }
|
|
|
- const result: Buffer[] = []
|
|
|
- while (data.includes(0xff)) {
|
|
|
- const pos = data.indexOf(0xff)
|
|
|
-
|
|
|
- result.push(data.slice(0, pos))
|
|
|
- result.push(Buffer.from([0xff, 0xff]))
|
|
|
-
|
|
|
- data = data.slice(pos + 1)
|
|
|
- }
|
|
|
-
|
|
|
- result.push(data)
|
|
|
- return Buffer.concat(result)
|
|
|
- }
|
|
|
-
|
|
|
async start (): Promise<void> {
|
|
|
this.socket = new Socket()
|
|
|
this.emitServiceMessage(`Connecting to ${this.profile.options.host}`)
|
|
|
@@ -124,6 +115,7 @@ export class TelnetSession extends BaseSession {
|
|
|
onData (data: Buffer): void {
|
|
|
if (!this.telnetProtocol && data[0] === TelnetCommands.IAC) {
|
|
|
this.telnetProtocol = true
|
|
|
+ this.middleware.push(new UnescapeFFMiddleware())
|
|
|
this.requestOption(TelnetCommands.DO, TelnetOptions.SUPPRESS_GO_AHEAD)
|
|
|
this.emitTelnet(TelnetCommands.WILL, TelnetOptions.TERMINAL_TYPE)
|
|
|
this.emitTelnet(TelnetCommands.WILL, TelnetOptions.NEGO_WINDOW_SIZE)
|
|
|
@@ -131,7 +123,7 @@ export class TelnetSession extends BaseSession {
|
|
|
if (this.telnetProtocol) {
|
|
|
data = this.processTelnetProtocol(data)
|
|
|
}
|
|
|
- this.streamProcessor.feedFromSession(data)
|
|
|
+ this.emitOutput(data)
|
|
|
}
|
|
|
|
|
|
emitTelnet (command: TelnetCommands, option: TelnetOptions): void {
|
|
|
@@ -190,7 +182,7 @@ export class TelnetSession extends BaseSession {
|
|
|
this.emitTelnet(TelnetCommands.WILL, option)
|
|
|
this.emitSize()
|
|
|
} else if (option === TelnetOptions.ECHO) {
|
|
|
- this.echoEnabled = true
|
|
|
+ this.streamProcessor.forceEcho = true
|
|
|
this.emitTelnet(TelnetCommands.WILL, option)
|
|
|
} else if (option === TelnetOptions.TERMINAL_TYPE) {
|
|
|
this.emitTelnet(TelnetCommands.WILL, option)
|
|
|
@@ -201,7 +193,7 @@ export class TelnetSession extends BaseSession {
|
|
|
}
|
|
|
if (command === TelnetCommands.DONT) {
|
|
|
if (option === TelnetOptions.ECHO) {
|
|
|
- this.echoEnabled = false
|
|
|
+ this.streamProcessor.forceEcho = false
|
|
|
this.emitTelnet(TelnetCommands.WONT, option)
|
|
|
} else {
|
|
|
this.logger.debug('(!) Unhandled option')
|
|
|
@@ -249,10 +241,7 @@ export class TelnetSession extends BaseSession {
|
|
|
}
|
|
|
|
|
|
write (data: Buffer): void {
|
|
|
- if (this.echoEnabled) {
|
|
|
- this.emitOutput(data)
|
|
|
- }
|
|
|
- this.streamProcessor.feedFromTerminal(data)
|
|
|
+ this.socket.write(data)
|
|
|
}
|
|
|
|
|
|
kill (_signal?: string): void {
|