From 8b5a646d17af43650447f20f370256dbc73b16ca Mon Sep 17 00:00:00 2001 From: Navan Chauhan Date: Fri, 8 Mar 2024 19:04:06 -0700 Subject: handle backspace/del in MTCP Telnet --- Sources/swift-gopher/gopherHandler.swift | 89 ++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 22 deletions(-) diff --git a/Sources/swift-gopher/gopherHandler.swift b/Sources/swift-gopher/gopherHandler.swift index bfca8de..a9a3167 100644 --- a/Sources/swift-gopher/gopherHandler.swift +++ b/Sources/swift-gopher/gopherHandler.swift @@ -29,34 +29,79 @@ final class GopherHandler: ChannelInboundHandler { self.disableGophermap = disableGophermap } - func channelRead(context: ChannelHandlerContext, data: NIOAny) { - let input = self.unwrapInboundIn(data) + private var buffer = ByteBuffer() + let delChar = Character(UnicodeScalar(127)) + let backspaceChar = Character(UnicodeScalar(8)) - guard let requestString = input.getString(at: 0, length: input.readableBytes) else { - return - } + func channelRead(context: ChannelHandlerContext, data: NIOAny) { + var input = self.unwrapInboundIn(data) + buffer.writeBuffer(&input) + + print(buffer.readableBytes) + + if let requestString = buffer.getString(at: 0, length: buffer.readableBytes) { + if requestString.firstIndex(of: "\r\n") != nil || requestString.firstIndex(of: "\n") != nil + || requestString.firstIndex(of: "\r") != nil + { // May not be necessary to use last two cases + if let remoteAddress = context.remoteAddress { + logger.info( + "Received request from \(remoteAddress) for '\(requestString.replacingOccurrences(of: "\r\n", with: "").replacingOccurrences(of: "\n", with: ""))'" + ) + } else { + logger.warning("Unable to retrieve remote address") + } - if let remoteAddress = context.remoteAddress { - logger.info( - "Received request from \(remoteAddress) for '\(requestString.replacingOccurrences(of: "\r\n", with: "").replacingOccurrences(of: "\n", with: ""))'" - ) - } else { - logger.warning("Unable to retrieve remote address") - } + var processedRequestString: String = requestString + // Check for backspace or delete and process them + if processedRequestString.contains(delChar) + || processedRequestString.contains(backspaceChar) + { + logger.info( + "Request contains delete character (ASCII code 127) or the backsapce character (ASCII code 8), processing delete sequences" + ) + + func processDeleteCharacter(_ input: String, _ asciiCode: Int = 8) -> String { + var result: [Character] = [] + for character in input { + if let asciiValue = character.asciiValue, asciiValue == asciiCode { + if !result.isEmpty { + result.removeLast() + } + } else { + result.append(character) + } + } + return String(result) + } - let response = processGopherRequest(requestString) + processedRequestString = processDeleteCharacter(requestString, 127) + processedRequestString = processDeleteCharacter(processedRequestString) // Could just combine in one statement if asciiCode is changed to asciiCodes: [Int] + } - var buffer: ByteBuffer + // for character in requestString { // Helpful for debugging + // if let scalar = character.unicodeScalars.first, scalar.value < 128 { + // print("\(character): \(scalar.value)") + // } else { + // print("\(character): Not an ASCII character") + // } + // } + + let response = processGopherRequest(processedRequestString) + var outputBuffer: ByteBuffer + switch response { + case .string(let string): + outputBuffer = context.channel.allocator.buffer(string: string) + case .data(let data): + outputBuffer = context.channel.allocator.buffer(bytes: data) + } - switch response { - case .string(let string): - buffer = context.channel.allocator.buffer(string: string) - case .data(let data): - buffer = context.channel.allocator.buffer(bytes: data) - } + context.writeAndFlush(self.wrapOutboundOut(outputBuffer)).whenComplete { _ in + context.close(mode: .all, promise: nil) + } - context.writeAndFlush(self.wrapOutboundOut(buffer)).whenComplete { _ in - context.close(mode: .all, promise: nil) + } else { + //print("No CR/LF") + } } } -- cgit v1.2.3