2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2017 Kevin Lamonte
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.io
.InputStream
;
32 import java
.io
.IOException
;
33 import java
.util
.ArrayList
;
35 import java
.util
.TreeMap
;
37 import jexer
.backend
.SessionInfo
;
38 import static jexer
.net
.TelnetSocket
.*;
41 * TelnetInputStream works with TelnetSocket to perform the telnet protocol.
43 public class TelnetInputStream
extends InputStream
implements SessionInfo
{
45 // ------------------------------------------------------------------------
46 // Constants --------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 // ------------------------------------------------------------------------
50 // Variables --------------------------------------------------------------
51 // ------------------------------------------------------------------------
54 * The root TelnetSocket that has my telnet protocol state.
56 private TelnetSocket master
;
59 * The raw socket's InputStream.
61 private InputStream input
;
64 * The telnet-aware OutputStream.
66 private TelnetOutputStream output
;
69 * Persistent read buffer. In practice this will only be used if the
70 * single-byte read() is called sometime.
72 private byte [] readBuffer
;
75 * Current writing position in readBuffer - what is passed into
78 private int readBufferEnd
;
81 * Current read position in readBuffer - what is passed to the client in
82 * response to this.read().
84 private int readBufferStart
;
89 private String username
= "";
94 private String language
= "en_US";
99 private int windowWidth
= 80;
102 * Text window height.
104 private int windowHeight
= 24;
107 * When true, the last read byte from the remote side was IAC.
109 private boolean iac
= false;
112 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
114 private boolean dowill
= false;
117 * The telnet option being negotiated.
119 private int dowillType
= 0;
122 * When true, we are waiting to see the end of the sub-negotiation
125 private boolean subnegEnd
= false;
128 * When true, the last byte read from the remote side was CR.
130 private boolean readCR
= false;
133 * The subnegotiation buffer.
135 private ArrayList
<Byte
> subnegBuffer
;
137 // ------------------------------------------------------------------------
138 // Constructors -----------------------------------------------------------
139 // ------------------------------------------------------------------------
142 * Package private constructor.
144 * @param master the master TelnetSocket
145 * @param input the underlying socket's InputStream
146 * @param output the telnet-aware OutputStream
148 TelnetInputStream(final TelnetSocket master
, final InputStream input
,
149 final TelnetOutputStream output
) {
151 this.master
= master
;
153 this.output
= output
;
155 // Setup new read buffer
156 readBuffer
= new byte[1024];
159 subnegBuffer
= new ArrayList
<Byte
>();
162 // ------------------------------------------------------------------------
163 // SessionInfo ------------------------------------------------------------
164 // ------------------------------------------------------------------------
169 * @return the username
171 public String
getUsername() {
172 return this.username
;
178 * @param username the value
180 public void setUsername(final String username
) {
181 this.username
= username
;
187 * @return the language
189 public String
getLanguage() {
190 return this.language
;
196 * @param language the value
198 public void setLanguage(final String language
) {
199 this.language
= language
;
203 * Text window width getter.
205 * @return the window width
207 public int getWindowWidth() {
212 * Text window height getter.
214 * @return the window height
216 public int getWindowHeight() {
221 * Re-query the text window size.
223 public void queryWindowSize() {
227 // ------------------------------------------------------------------------
228 // InputStream ------------------------------------------------------------
229 // ------------------------------------------------------------------------
232 * Returns an estimate of the number of bytes that can be read (or
233 * skipped over) from this input stream without blocking by the next
234 * invocation of a method for this input stream.
236 * @return an estimate of the number of bytes that can be read (or
237 * skipped over) from this input stream without blocking or 0 when it
238 * reaches the end of the input stream.
239 * @throws IOException if an I/O error occurs
242 public int available() throws IOException
{
243 if (readBuffer
== null) {
244 throw new IOException("InputStream is closed");
246 if (readBufferEnd
- readBufferStart
> 0) {
247 return (readBufferEnd
- readBufferStart
);
249 return input
.available();
253 * Closes this input stream and releases any system resources associated
256 * @throws IOException if an I/O error occurs
259 public void close() throws IOException
{
260 if (readBuffer
!= null) {
267 * Marks the current position in this input stream.
269 * @param readLimit the maximum limit of bytes that can be read before
270 * the mark position becomes invalid
273 public void mark(final int readLimit
) {
278 * Tests if this input stream supports the mark and reset methods.
280 * @return true if this stream instance supports the mark and reset
281 * methods; false otherwise
284 public boolean markSupported() {
289 * Reads the next byte of data from the input stream.
291 * @return the next byte of data, or -1 if there is no more data because
292 * the end of the stream has been reached.
293 * @throws IOException if an I/O error occurs
296 public int read() throws IOException
{
298 // If the post-processed buffer has bytes, use that.
299 if (readBufferEnd
- readBufferStart
> 0) {
301 return readBuffer
[readBufferStart
- 1];
304 // The buffer is empty, so reset the indexes to 0.
308 // Read some fresh data and run it through the telnet protocol.
309 int rc
= readImpl(readBuffer
, readBufferEnd
,
310 readBuffer
.length
- readBufferEnd
);
312 // If we got something, return it.
315 return readBuffer
[readBufferStart
- 1];
317 // If we read 0, I screwed up big time.
325 * Reads some number of bytes from the input stream and stores them into
326 * the buffer array b.
328 * @param b the buffer into which the data is read.
329 * @return the total number of bytes read into the buffer, or -1 if there
330 * is no more data because the end of the stream has been reached.
331 * @throws IOException if an I/O error occurs
334 public int read(final byte[] b
) throws IOException
{
335 return read(b
, 0, b
.length
);
339 * Reads up to len bytes of data from the input stream into an array of
342 * @param b the buffer into which the data is read.
343 * @param off the start offset in array b at which the data is written.
344 * @param len the maximum number of bytes to read.
345 * @return the total number of bytes read into the buffer, or -1 if there
346 * is no more data because the end of the stream has been reached.
347 * @throws IOException if an I/O error occurs
350 public int read(final byte[] b
, final int off
,
351 final int len
) throws IOException
{
353 // The only time we can return 0 is if len is 0, as per the
354 // InputStream contract.
359 // If the post-processed buffer has bytes, use that.
360 if (readBufferEnd
- readBufferStart
> 0) {
361 int n
= Math
.min(len
, readBufferEnd
- readBufferStart
);
362 System
.arraycopy(b
, off
, readBuffer
, readBufferStart
, n
);
363 readBufferStart
+= n
;
367 // The buffer is empty, so reset the indexes to 0.
371 // The maximum number of bytes we will ask for will definitely be
372 // within the bounds of what we can return in a single call.
373 int n
= Math
.min(len
, readBuffer
.length
);
375 // Read some fresh data and run it through the telnet protocol.
376 int rc
= readImpl(readBuffer
, readBufferEnd
, n
);
378 // If we got something, return it.
380 System
.arraycopy(readBuffer
, 0, b
, off
, rc
);
383 // If we read 0, I screwed up big time.
391 * Repositions this stream to the position at the time the mark method
392 * was last called on this input stream. This is not supported by
393 * TelnetInputStream, so IOException is always thrown.
395 * @throws IOException if this function is used
398 public void reset() throws IOException
{
399 throw new IOException("InputStream does not support mark/reset");
403 * Skips over and discards n bytes of data from this input stream.
405 * @param n the number of bytes to be skipped
406 * @return the actual number of bytes skipped
407 * @throws IOException if an I/O error occurs
410 public long skip(final long n
) throws IOException
{
414 for (int i
= 0; i
< n
; i
++) {
420 // ------------------------------------------------------------------------
421 // TelnetInputStream ------------------------------------------------------
422 // ------------------------------------------------------------------------
425 * For debugging, return a descriptive string for this telnet option.
426 * These are pulled from: http://www.iana.org/assignments/telnet-options
428 * @param option the telnet option byte
429 * @return a string describing the telnet option code
431 @SuppressWarnings("unused")
432 private String
optionString(final int option
) {
434 case 0: return "Binary Transmission";
435 case 1: return "Echo";
436 case 2: return "Reconnection";
437 case 3: return "Suppress Go Ahead";
438 case 4: return "Approx Message Size Negotiation";
439 case 5: return "Status";
440 case 6: return "Timing Mark";
441 case 7: return "Remote Controlled Trans and Echo";
442 case 8: return "Output Line Width";
443 case 9: return "Output Page Size";
444 case 10: return "Output Carriage-Return Disposition";
445 case 11: return "Output Horizontal Tab Stops";
446 case 12: return "Output Horizontal Tab Disposition";
447 case 13: return "Output Formfeed Disposition";
448 case 14: return "Output Vertical Tabstops";
449 case 15: return "Output Vertical Tab Disposition";
450 case 16: return "Output Linefeed Disposition";
451 case 17: return "Extended ASCII";
452 case 18: return "Logout";
453 case 19: return "Byte Macro";
454 case 20: return "Data Entry Terminal";
455 case 21: return "SUPDUP";
456 case 22: return "SUPDUP Output";
457 case 23: return "Send Location";
458 case 24: return "Terminal Type";
459 case 25: return "End of Record";
460 case 26: return "TACACS User Identification";
461 case 27: return "Output Marking";
462 case 28: return "Terminal Location Number";
463 case 29: return "Telnet 3270 Regime";
464 case 30: return "X.3 PAD";
465 case 31: return "Negotiate About Window Size";
466 case 32: return "Terminal Speed";
467 case 33: return "Remote Flow Control";
468 case 34: return "Linemode";
469 case 35: return "X Display Location";
470 case 36: return "Environment Option";
471 case 37: return "Authentication Option";
472 case 38: return "Encryption Option";
473 case 39: return "New Environment Option";
474 case 40: return "TN3270E";
475 case 41: return "XAUTH";
476 case 42: return "CHARSET";
477 case 43: return "Telnet Remote Serial Port (RSP)";
478 case 44: return "Com Port Control Option";
479 case 45: return "Telnet Suppress Local Echo";
480 case 46: return "Telnet Start TLS";
481 case 47: return "KERMIT";
482 case 48: return "SEND-URL";
483 case 49: return "FORWARD_X";
484 case 138: return "TELOPT PRAGMA LOGON";
485 case 139: return "TELOPT SSPI LOGON";
486 case 140: return "TELOPT PRAGMA HEARTBEAT";
487 case 255: return "Extended-Options-List";
489 if ((option
>= 50) && (option
<= 137)) {
492 return "UNKNOWN - OTHER";
497 * Send a DO/DON'T/WILL/WON'T response to the remote side.
499 * @param response a TELNET_DO/DONT/WILL/WONT byte
500 * @param option telnet option byte (binary mode, term type, etc.)
501 * @throws IOException if an I/O error occurs
503 private void respond(final int response
,
504 final int option
) throws IOException
{
506 byte [] buffer
= new byte[3];
507 buffer
[0] = (byte)TELNET_IAC
;
508 buffer
[1] = (byte)response
;
509 buffer
[2] = (byte)option
;
511 output
.rawWrite(buffer
);
515 * Tell the remote side we WILL support an option.
517 * @param option telnet option byte (binary mode, term type, etc.)
518 * @throws IOException if an I/O error occurs
520 private void WILL(final int option
) throws IOException
{
521 respond(TELNET_WILL
, option
);
525 * Tell the remote side we WON'T support an option.
527 * @param option telnet option byte (binary mode, term type, etc.)
528 * @throws IOException if an I/O error occurs
530 private void WONT(final int option
) throws IOException
{
531 respond(TELNET_WONT
, option
);
535 * Tell the remote side we DO support an option.
537 * @param option telnet option byte (binary mode, term type, etc.)
538 * @throws IOException if an I/O error occurs
540 private void DO(final int option
) throws IOException
{
541 respond(TELNET_DO
, option
);
545 * Tell the remote side we DON'T support an option.
547 * @param option telnet option byte (binary mode, term type, etc.)
548 * @throws IOException if an I/O error occurs
550 private void DONT(final int option
) throws IOException
{
551 respond(TELNET_DONT
, option
);
555 * Tell the remote side we WON't or DON'T support an option.
557 * @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
558 * @param option telnet option byte (binary mode, term type, etc.)
559 * @throws IOException if an I/O error occurs
561 private void refuse(final int remoteQuery
,
562 final int option
) throws IOException
{
564 if (remoteQuery
== TELNET_DO
) {
572 * Build sub-negotiation packet (RFC 855).
574 * @param option telnet option
575 * @param response output buffer of response bytes
576 * @throws IOException if an I/O error occurs
578 private void telnetSendSubnegResponse(final int option
,
579 final byte [] response
) throws IOException
{
581 byte [] buffer
= new byte[response
.length
+ 5];
582 buffer
[0] = (byte)TELNET_IAC
;
583 buffer
[1] = (byte)TELNET_SB
;
584 buffer
[2] = (byte)option
;
585 System
.arraycopy(response
, 0, buffer
, 3, response
.length
);
586 buffer
[response
.length
+ 3] = (byte)TELNET_IAC
;
587 buffer
[response
.length
+ 4] = (byte)TELNET_SE
;
588 output
.rawWrite(buffer
);
592 * Telnet option: Terminal Speed (RFC 1079). Client side.
594 * @throws IOException if an I/O error occurs
596 private void telnetSendTerminalSpeed() throws IOException
{
597 byte [] response
= {0, '3', '8', '4', '0', '0', ',',
598 '3', '8', '4', '0', '0'};
599 telnetSendSubnegResponse(32, response
);
603 * Telnet option: Terminal Type (RFC 1091). Client side.
605 * @throws IOException if an I/O error occurs
607 private void telnetSendTerminalType() throws IOException
{
608 byte [] response
= {0, 'v', 't', '1', '0', '0' };
609 telnetSendSubnegResponse(24, response
);
613 * Telnet option: Terminal Type (RFC 1091). Server side.
615 * @throws IOException if an I/O error occurs
617 private void requestTerminalType() throws IOException
{
618 byte [] response
= new byte[1];
620 telnetSendSubnegResponse(24, response
);
624 * Telnet option: Terminal Speed (RFC 1079). Server side.
626 * @throws IOException if an I/O error occurs
628 private void requestTerminalSpeed() throws IOException
{
629 byte [] response
= new byte[1];
631 telnetSendSubnegResponse(32, response
);
635 * Telnet option: New Environment (RFC 1572). Server side.
637 * @throws IOException if an I/O error occurs
639 private void requestEnvironment() throws IOException
{
640 byte [] response
= new byte[1];
642 telnetSendSubnegResponse(39, response
);
646 * Send the options we want to negotiate on.
648 * <p>The options we use are:
652 * Binary Transmission RFC 856
653 * Suppress Go Ahead RFC 858
654 * Negotiate About Window Size RFC 1073
655 * Terminal Type RFC 1091
656 * Terminal Speed RFC 1079
657 * New Environment RFC 1572
659 * When run as a server:
663 * @throws IOException if an I/O error occurs
665 void telnetSendOptions() throws IOException
{
666 if (master
.binaryMode
== false) {
667 // Binary Transmission: must ask both do and will
672 if (master
.goAhead
== true) {
678 // Server only options
679 if (master
.isServer
== true) {
680 // Enable Echo - I echo to them, they do not echo back to me.
684 if (master
.doTermType
== true) {
685 // Terminal type - request it
689 if (master
.doTermSpeed
== true) {
690 // Terminal speed - request it
694 if (master
.doNAWS
== true) {
699 if (master
.doEnvironment
== true) {
700 // Environment - request it
706 if (master
.doTermType
== true) {
707 // Terminal type - request it
711 if (master
.doTermSpeed
== true) {
712 // Terminal speed - request it
716 if (master
.doNAWS
== true) {
721 if (master
.doEnvironment
== true) {
722 // Environment - request it
732 * New Environment parsing state.
734 private enum EnvState
{
742 * Handle the New Environment option. Note that this implementation
743 * fails to handle ESC as defined in RFC 1572.
745 private void handleNewEnvironment() {
746 Map
<String
, String
> newEnv
= new TreeMap
<String
, String
>();
748 EnvState state
= EnvState
.INIT
;
749 StringBuilder name
= new StringBuilder();
750 StringBuilder value
= new StringBuilder();
753 System.err.printf("handleNewEnvironment() %d bytes\n",
754 subnegBuffer.size());
757 for (int i
= 1; i
< subnegBuffer
.size(); i
++) {
758 Byte b
= subnegBuffer
.get(i
);
760 System.err.printf(" b: %c %d 0x%02x\n", (char)b.byteValue(),
769 state
= EnvState
.TYPE
;
771 // The other side isn't following the rules, see ya.
777 // Looking for "VAR" or "USERVAR"
780 state
= EnvState
.NAME
;
781 name
= new StringBuilder();
784 state
= EnvState
.NAME
;
785 name
= new StringBuilder();
787 // The other side isn't following the rules, see ya
793 // Looking for "VALUE" or a name byte
796 state
= EnvState
.VALUE
;
797 value
= new StringBuilder();
799 // Take it as an environment variable name/key byte
800 name
.append((char)b
.byteValue());
806 // Looking for "VAR", "USERVAR", or a name byte, or the end
809 state
= EnvState
.NAME
;
810 if (value
.length() > 0) {
812 System.err.printf("NAME: '%s' VALUE: '%s'\n",
815 newEnv
.put(name
.toString(), value
.toString());
817 name
= new StringBuilder();
820 state
= EnvState
.NAME
;
821 if (value
.length() > 0) {
823 System.err.printf("NAME: '%s' VALUE: '%s'\n",
826 newEnv
.put(name
.toString(), value
.toString());
828 name
= new StringBuilder();
830 // Take it as an environment variable value byte
831 value
.append((char)b
.byteValue());
836 throw new RuntimeException("Invalid state: " + state
);
841 if ((name
.length() > 0) && (value
.length() > 0)) {
843 System.err.printf("NAME: '%s' VALUE: '%s'\n", name, value);
845 newEnv
.put(name
.toString(), value
.toString());
848 for (String key
: newEnv
.keySet()) {
849 if (key
.equals("LANG")) {
850 language
= newEnv
.get(key
);
852 if (key
.equals("LOGNAME")) {
853 username
= newEnv
.get(key
);
855 if (key
.equals("USER")) {
856 username
= newEnv
.get(key
);
862 * Handle an option sub-negotiation.
864 * @throws IOException if an I/O error occurs
866 private void handleSubneg() throws IOException
{
869 // Sanity check: there must be at least 1 byte in subnegBuffer
870 if (subnegBuffer
.size() < 1) {
871 // Buffer too small: the other side is a broken telnetd, it did
872 // not send the right sub-negotiation data. Bail out now.
875 option
= subnegBuffer
.get(0);
881 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
882 // Server sent "SEND", we say "IS"
883 telnetSendTerminalType();
885 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
886 // Client sent "IS", record it
887 StringBuilder terminalString
= new StringBuilder();
888 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
889 terminalString
.append((char)subnegBuffer
.
892 master
.terminalType
= terminalString
.toString();
894 System.err.printf("terminal type: '%s'\n",
895 master.terminalType);
902 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
903 // Server sent "SEND", we say "IS"
904 telnetSendTerminalSpeed();
906 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
907 // Client sent "IS", record it
908 StringBuilder speedString
= new StringBuilder();
909 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
910 speedString
.append((char)subnegBuffer
.get(i
).byteValue());
912 master
.terminalSpeed
= speedString
.toString();
914 System.err.printf("terminal speed: '%s'\n",
915 master.terminalSpeed);
922 if (subnegBuffer
.size() >= 5) {
926 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
929 windowWidth
= subnegBuffer
.get(i
) * 256;
932 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
935 windowWidth
+= subnegBuffer
.get(i
);
938 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
941 windowHeight
= subnegBuffer
.get(i
) * 256;
944 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
947 windowHeight
+= subnegBuffer
.get(i
);
953 handleNewEnvironment();
963 * Reads up to len bytes of data from the input stream into an array of
966 * @param buf the buffer into which the data is read.
967 * @param off the start offset in array b at which the data is written.
968 * @param len the maximum number of bytes to read.
969 * @return the total number of bytes read into the buffer, or -1 if there
970 * is no more data because the end of the stream has been reached.
971 * @throws IOException if an I/O error occurs
973 private int readImpl(final byte[] buf
, final int off
,
974 final int len
) throws IOException
{
978 // The current writing position in buf.
981 // We will keep trying to read() until we have something to return.
984 // Read up to len bytes
985 byte [] buffer
= new byte[len
];
988 // Read some data from the other end
989 int rc
= input
.read(buffer
);
991 // Check for EOF or error
996 // EOF, just return it.
1000 // Loop through the read bytes
1001 for (int i
= 0; i
< bufferN
; i
++) {
1004 if (subnegEnd
== true) {
1005 // Looking for IAC SE to end this subnegotiation
1006 if (b
== (byte)TELNET_SE
) {
1012 } else if (b
== (byte)TELNET_IAC
) {
1014 // An argument to the subnegotiation option
1015 subnegBuffer
.add((byte)TELNET_IAC
);
1020 // An argument to the subnegotiation option
1021 subnegBuffer
.add(b
);
1026 // Look for DO/DON'T/WILL/WON'T option
1027 if (dowill
== true) {
1033 // Binary Transmission
1034 if (dowillType
== (byte)TELNET_WILL
) {
1035 // Server will use binary transmission, yay.
1036 master
.binaryMode
= true;
1037 } else if (dowillType
== (byte)TELNET_DO
) {
1038 // Server asks for binary transmission.
1040 master
.binaryMode
= true;
1041 } else if (dowillType
== (byte)TELNET_WONT
) {
1042 // We're screwed, server won't do binary
1044 master
.binaryMode
= false;
1046 // Server demands NVT ASCII mode.
1047 master
.binaryMode
= false;
1053 if (dowillType
== (byte)TELNET_WILL
) {
1054 // Server will use echo, yay.
1055 master
.echoMode
= true;
1056 } else if (dowillType
== (byte)TELNET_DO
) {
1057 // Server asks for echo.
1059 master
.echoMode
= true;
1060 } else if (dowillType
== (byte)TELNET_WONT
) {
1061 // We're screwed, server won't do echo.
1062 master
.echoMode
= false;
1064 // Server demands no echo.
1065 master
.echoMode
= false;
1070 // Suppress Go Ahead
1071 if (dowillType
== (byte)TELNET_WILL
) {
1072 // Server will use suppress go-ahead, yay.
1073 master
.goAhead
= false;
1074 } else if (dowillType
== (byte)TELNET_DO
) {
1075 // Server asks for suppress go-ahead.
1077 master
.goAhead
= false;
1078 } else if (dowillType
== (byte)TELNET_WONT
) {
1079 // We're screwed, server won't do suppress
1081 master
.goAhead
= true;
1083 // Server demands Go-Ahead mode.
1084 master
.goAhead
= true;
1089 // Terminal Type - send what's in TERM
1090 if (dowillType
== (byte)TELNET_WILL
) {
1091 // Server will use terminal type, yay.
1093 && master
.doTermType
1095 requestTerminalType();
1096 master
.doTermType
= false;
1097 } else if (!master
.isServer
) {
1098 master
.doTermType
= true;
1100 } else if (dowillType
== (byte)TELNET_DO
) {
1101 // Server asks for terminal type.
1103 master
.doTermType
= true;
1104 } else if (dowillType
== (byte)TELNET_WONT
) {
1105 // We're screwed, server won't do terminal type.
1106 master
.doTermType
= false;
1108 // Server will not listen to terminal type.
1109 master
.doTermType
= false;
1115 if (dowillType
== (byte)TELNET_WILL
) {
1116 // Server will use NAWS, yay.
1117 master
.doNAWS
= true;
1118 // NAWS cannot be requested by the server, it is
1119 // only sent by the client.
1120 } else if (dowillType
== (byte)TELNET_DO
) {
1121 // Server asks for NAWS.
1123 master
.doNAWS
= true;
1124 } else if (dowillType
== (byte)TELNET_WONT
) {
1125 // Server won't do NAWS.
1126 master
.doNAWS
= false;
1128 // Server will not listen to NAWS.
1129 master
.doNAWS
= false;
1135 if (dowillType
== (byte)TELNET_WILL
) {
1136 // Server will use terminal speed, yay.
1138 && master
.doTermSpeed
1140 requestTerminalSpeed();
1141 master
.doTermSpeed
= false;
1142 } else if (!master
.isServer
) {
1143 master
.doTermSpeed
= true;
1145 } else if (dowillType
== (byte)TELNET_DO
) {
1146 // Server asks for terminal speed.
1148 master
.doTermSpeed
= true;
1149 } else if (dowillType
== (byte)TELNET_WONT
) {
1150 // We're screwed, server won't do terminal speed.
1151 master
.doTermSpeed
= false;
1153 // Server will not listen to terminal speed.
1154 master
.doTermSpeed
= false;
1160 if (dowillType
== (byte)TELNET_WILL
) {
1161 // Server will use NewEnvironment, yay.
1163 && master
.doEnvironment
1165 requestEnvironment();
1166 master
.doEnvironment
= false;
1167 } else if (!master
.isServer
) {
1168 master
.doEnvironment
= true;
1170 } else if (dowillType
== (byte)TELNET_DO
) {
1171 // Server asks for NewEnvironment.
1173 master
.doEnvironment
= true;
1174 } else if (dowillType
== (byte)TELNET_WONT
) {
1175 // Server won't do NewEnvironment.
1176 master
.doEnvironment
= false;
1178 // Server will not listen to New Environment.
1179 master
.doEnvironment
= false;
1185 // Other side asked for something we don't
1186 // understand. Tell them we will not do this option.
1187 refuse(dowillType
, b
);
1193 } // if (dowill == true)
1195 // Perform read processing
1196 if (b
== (byte)TELNET_IAC
) {
1201 buf
[bufN
++] = (byte)TELNET_IAC
;
1212 case (byte)TELNET_SE
:
1213 // log.debug1(" END Sub-Negotiation");
1215 case (byte)TELNET_NOP
:
1216 // log.debug1(" NOP");
1218 case (byte)TELNET_DM
:
1219 // log.debug1(" Data Mark");
1221 case (byte)TELNET_BRK
:
1222 // log.debug1(" Break");
1224 case (byte)TELNET_IP
:
1225 // log.debug1(" Interrupt Process");
1227 case (byte)TELNET_AO
:
1228 // log.debug1(" Abort Output");
1230 case (byte)TELNET_AYT
:
1231 // log.debug1(" Are You There?");
1233 case (byte)TELNET_EC
:
1234 // log.debug1(" Erase Character");
1236 case (byte)TELNET_EL
:
1237 // log.debug1(" Erase Line");
1239 case (byte)TELNET_GA
:
1240 // log.debug1(" Go Ahead");
1242 case (byte)TELNET_SB
:
1243 // log.debug1(" START Sub-Negotiation");
1244 // From here we wait for the IAC SE
1246 subnegBuffer
.clear();
1248 case (byte)TELNET_WILL
:
1249 // log.debug1(" WILL");
1253 case (byte)TELNET_WONT
:
1254 // log.debug1(" WON'T");
1258 case (byte)TELNET_DO
:
1259 // log.debug1(" DO");
1263 if (master
.binaryMode
== true) {
1264 // log.debug1("Telnet DO in binary mode");
1268 case (byte)TELNET_DONT
:
1269 // log.debug1(" DON'T");
1274 // This should be equivalent to IAC NOP
1275 // log.debug1("Will treat as IAC NOP");
1281 } // if (iac == true)
1284 * All of the regular IAC processing is completed at this
1285 * point. Now we need to handle the CR and CR LF cases.
1287 * According to RFC 854, in NVT ASCII mode:
1292 if (master
.binaryMode
== false) {
1295 if (readCR
== true) {
1296 // This is CR LF. Send CR LF and turn the cr
1303 // This is bare LF. Send LF.
1309 if (readCR
== true) {
1310 // This is CR NUL. Send CR and turn the cr
1316 // This is bare NUL. Send NUL.
1317 buf
[bufN
++] = C_NUL
;
1322 if (readCR
== true) {
1323 // This is CR CR. Send a CR NUL and leave
1326 buf
[bufN
++] = C_NUL
;
1329 // This is the first CR. Set the cr flag.
1334 if (readCR
== true) {
1335 // This was a bare CR in the stream.
1340 // This is a regular character. Pass it on.
1346 * This is the case for any of:
1348 * 1) A NVT ASCII character that isn't CR, LF, or
1351 * 2) A NVT binary character.
1353 * For all of these cases, we just pass the character on.
1357 } // if (b == TELNET_IAC)
1359 } // for (int i = 0; i < bufferN; i++)
1361 } while (bufN
== 0);
1363 // Return bytes read