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 final class TelnetInputStream
extends InputStream
44 implements SessionInfo
{
46 // ------------------------------------------------------------------------
47 // Constants --------------------------------------------------------------
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
51 // Variables --------------------------------------------------------------
52 // ------------------------------------------------------------------------
55 * The root TelnetSocket that has my telnet protocol state.
57 private TelnetSocket master
;
60 * The raw socket's InputStream.
62 private InputStream input
;
65 * The telnet-aware OutputStream.
67 private TelnetOutputStream output
;
70 * Persistent read buffer. In practice this will only be used if the
71 * single-byte read() is called sometime.
73 private byte [] readBuffer
;
76 * Current writing position in readBuffer - what is passed into
79 private int readBufferEnd
;
82 * Current read position in readBuffer - what is passed to the client in
83 * response to this.read().
85 private int readBufferStart
;
90 private String username
= "";
95 private String language
= "en_US";
100 private int windowWidth
= 80;
103 * Text window height.
105 private int windowHeight
= 24;
108 * When true, the last read byte from the remote side was IAC.
110 private boolean iac
= false;
113 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
115 private boolean dowill
= false;
118 * The telnet option being negotiated.
120 private int dowillType
= 0;
123 * When true, we are waiting to see the end of the sub-negotiation
126 private boolean subnegEnd
= false;
129 * When true, the last byte read from the remote side was CR.
131 private boolean readCR
= false;
134 * The subnegotiation buffer.
136 private ArrayList
<Byte
> subnegBuffer
;
138 // ------------------------------------------------------------------------
139 // Constructors -----------------------------------------------------------
140 // ------------------------------------------------------------------------
143 * Package private constructor.
145 * @param master the master TelnetSocket
146 * @param input the underlying socket's InputStream
147 * @param output the telnet-aware OutputStream
149 TelnetInputStream(final TelnetSocket master
, final InputStream input
,
150 final TelnetOutputStream output
) {
152 this.master
= master
;
154 this.output
= output
;
156 // Setup new read buffer
157 readBuffer
= new byte[1024];
160 subnegBuffer
= new ArrayList
<Byte
>();
163 // ------------------------------------------------------------------------
164 // SessionInfo ------------------------------------------------------------
165 // ------------------------------------------------------------------------
170 * @return the username
172 public String
getUsername() {
173 return this.username
;
179 * @param username the value
181 public void setUsername(final String username
) {
182 this.username
= username
;
188 * @return the language
190 public String
getLanguage() {
191 return this.language
;
197 * @param language the value
199 public void setLanguage(final String language
) {
200 this.language
= language
;
204 * Text window width getter.
206 * @return the window width
208 public int getWindowWidth() {
213 * Text window height getter.
215 * @return the window height
217 public int getWindowHeight() {
222 * Re-query the text window size.
224 public void queryWindowSize() {
228 // ------------------------------------------------------------------------
229 // InputStream ------------------------------------------------------------
230 // ------------------------------------------------------------------------
233 * Returns an estimate of the number of bytes that can be read (or
234 * skipped over) from this input stream without blocking by the next
235 * invocation of a method for this input stream.
237 * @return an estimate of the number of bytes that can be read (or
238 * skipped over) from this input stream without blocking or 0 when it
239 * reaches the end of the input stream.
240 * @throws IOException if an I/O error occurs
243 public int available() throws IOException
{
244 if (readBuffer
== null) {
245 throw new IOException("InputStream is closed");
247 if (readBufferEnd
- readBufferStart
> 0) {
248 return (readBufferEnd
- readBufferStart
);
250 return input
.available();
254 * Closes this input stream and releases any system resources associated
257 * @throws IOException if an I/O error occurs
260 public void close() throws IOException
{
261 if (readBuffer
!= null) {
268 * Marks the current position in this input stream.
270 * @param readLimit the maximum limit of bytes that can be read before
271 * the mark position becomes invalid
274 public void mark(final int readLimit
) {
279 * Tests if this input stream supports the mark and reset methods.
281 * @return true if this stream instance supports the mark and reset
282 * methods; false otherwise
285 public boolean markSupported() {
290 * Reads the next byte of data from the input stream.
292 * @return the next byte of data, or -1 if there is no more data because
293 * the end of the stream has been reached.
294 * @throws IOException if an I/O error occurs
297 public int read() throws IOException
{
299 // If the post-processed buffer has bytes, use that.
300 if (readBufferEnd
- readBufferStart
> 0) {
302 return readBuffer
[readBufferStart
- 1];
305 // The buffer is empty, so reset the indexes to 0.
309 // Read some fresh data and run it through the telnet protocol.
310 int rc
= readImpl(readBuffer
, readBufferEnd
,
311 readBuffer
.length
- readBufferEnd
);
313 // If we got something, return it.
316 return readBuffer
[readBufferStart
- 1];
318 // If we read 0, I screwed up big time.
326 * Reads some number of bytes from the input stream and stores them into
327 * the buffer array b.
329 * @param b the buffer into which the data is read.
330 * @return the total number of bytes read into the buffer, or -1 if there
331 * is no more data because the end of the stream has been reached.
332 * @throws IOException if an I/O error occurs
335 public int read(final byte[] b
) throws IOException
{
336 return read(b
, 0, b
.length
);
340 * Reads up to len bytes of data from the input stream into an array of
343 * @param b the buffer into which the data is read.
344 * @param off the start offset in array b at which the data is written.
345 * @param len the maximum number of bytes to read.
346 * @return the total number of bytes read into the buffer, or -1 if there
347 * is no more data because the end of the stream has been reached.
348 * @throws IOException if an I/O error occurs
351 public int read(final byte[] b
, final int off
,
352 final int len
) throws IOException
{
354 // The only time we can return 0 is if len is 0, as per the
355 // InputStream contract.
360 // If the post-processed buffer has bytes, use that.
361 if (readBufferEnd
- readBufferStart
> 0) {
362 int n
= Math
.min(len
, readBufferEnd
- readBufferStart
);
363 System
.arraycopy(b
, off
, readBuffer
, readBufferStart
, n
);
364 readBufferStart
+= n
;
368 // The buffer is empty, so reset the indexes to 0.
372 // The maximum number of bytes we will ask for will definitely be
373 // within the bounds of what we can return in a single call.
374 int n
= Math
.min(len
, readBuffer
.length
);
376 // Read some fresh data and run it through the telnet protocol.
377 int rc
= readImpl(readBuffer
, readBufferEnd
, n
);
379 // If we got something, return it.
381 System
.arraycopy(readBuffer
, 0, b
, off
, rc
);
384 // If we read 0, I screwed up big time.
392 * Repositions this stream to the position at the time the mark method
393 * was last called on this input stream. This is not supported by
394 * TelnetInputStream, so IOException is always thrown.
396 * @throws IOException if this function is used
399 public void reset() throws IOException
{
400 throw new IOException("InputStream does not support mark/reset");
404 * Skips over and discards n bytes of data from this input stream.
406 * @param n the number of bytes to be skipped
407 * @return the actual number of bytes skipped
408 * @throws IOException if an I/O error occurs
411 public long skip(final long n
) throws IOException
{
415 for (int i
= 0; i
< n
; i
++) {
421 // ------------------------------------------------------------------------
422 // TelnetInputStream ------------------------------------------------------
423 // ------------------------------------------------------------------------
426 * For debugging, return a descriptive string for this telnet option.
427 * These are pulled from: http://www.iana.org/assignments/telnet-options
429 * @param option the telnet option byte
430 * @return a string describing the telnet option code
432 @SuppressWarnings("unused")
433 private String
optionString(final int option
) {
435 case 0: return "Binary Transmission";
436 case 1: return "Echo";
437 case 2: return "Reconnection";
438 case 3: return "Suppress Go Ahead";
439 case 4: return "Approx Message Size Negotiation";
440 case 5: return "Status";
441 case 6: return "Timing Mark";
442 case 7: return "Remote Controlled Trans and Echo";
443 case 8: return "Output Line Width";
444 case 9: return "Output Page Size";
445 case 10: return "Output Carriage-Return Disposition";
446 case 11: return "Output Horizontal Tab Stops";
447 case 12: return "Output Horizontal Tab Disposition";
448 case 13: return "Output Formfeed Disposition";
449 case 14: return "Output Vertical Tabstops";
450 case 15: return "Output Vertical Tab Disposition";
451 case 16: return "Output Linefeed Disposition";
452 case 17: return "Extended ASCII";
453 case 18: return "Logout";
454 case 19: return "Byte Macro";
455 case 20: return "Data Entry Terminal";
456 case 21: return "SUPDUP";
457 case 22: return "SUPDUP Output";
458 case 23: return "Send Location";
459 case 24: return "Terminal Type";
460 case 25: return "End of Record";
461 case 26: return "TACACS User Identification";
462 case 27: return "Output Marking";
463 case 28: return "Terminal Location Number";
464 case 29: return "Telnet 3270 Regime";
465 case 30: return "X.3 PAD";
466 case 31: return "Negotiate About Window Size";
467 case 32: return "Terminal Speed";
468 case 33: return "Remote Flow Control";
469 case 34: return "Linemode";
470 case 35: return "X Display Location";
471 case 36: return "Environment Option";
472 case 37: return "Authentication Option";
473 case 38: return "Encryption Option";
474 case 39: return "New Environment Option";
475 case 40: return "TN3270E";
476 case 41: return "XAUTH";
477 case 42: return "CHARSET";
478 case 43: return "Telnet Remote Serial Port (RSP)";
479 case 44: return "Com Port Control Option";
480 case 45: return "Telnet Suppress Local Echo";
481 case 46: return "Telnet Start TLS";
482 case 47: return "KERMIT";
483 case 48: return "SEND-URL";
484 case 49: return "FORWARD_X";
485 case 138: return "TELOPT PRAGMA LOGON";
486 case 139: return "TELOPT SSPI LOGON";
487 case 140: return "TELOPT PRAGMA HEARTBEAT";
488 case 255: return "Extended-Options-List";
490 if ((option
>= 50) && (option
<= 137)) {
493 return "UNKNOWN - OTHER";
498 * Send a DO/DON'T/WILL/WON'T response to the remote side.
500 * @param response a TELNET_DO/DONT/WILL/WONT byte
501 * @param option telnet option byte (binary mode, term type, etc.)
502 * @throws IOException if an I/O error occurs
504 private void respond(final int response
,
505 final int option
) throws IOException
{
507 byte [] buffer
= new byte[3];
508 buffer
[0] = (byte)TELNET_IAC
;
509 buffer
[1] = (byte)response
;
510 buffer
[2] = (byte)option
;
512 output
.rawWrite(buffer
);
516 * Tell the remote side we WILL support an option.
518 * @param option telnet option byte (binary mode, term type, etc.)
519 * @throws IOException if an I/O error occurs
521 private void WILL(final int option
) throws IOException
{
522 respond(TELNET_WILL
, option
);
526 * Tell the remote side we WON'T support an option.
528 * @param option telnet option byte (binary mode, term type, etc.)
529 * @throws IOException if an I/O error occurs
531 private void WONT(final int option
) throws IOException
{
532 respond(TELNET_WONT
, option
);
536 * Tell the remote side we DO support an option.
538 * @param option telnet option byte (binary mode, term type, etc.)
539 * @throws IOException if an I/O error occurs
541 private void DO(final int option
) throws IOException
{
542 respond(TELNET_DO
, option
);
546 * Tell the remote side we DON'T support an option.
548 * @param option telnet option byte (binary mode, term type, etc.)
549 * @throws IOException if an I/O error occurs
551 private void DONT(final int option
) throws IOException
{
552 respond(TELNET_DONT
, option
);
556 * Tell the remote side we WON't or DON'T support an option.
558 * @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
559 * @param option telnet option byte (binary mode, term type, etc.)
560 * @throws IOException if an I/O error occurs
562 private void refuse(final int remoteQuery
,
563 final int option
) throws IOException
{
565 if (remoteQuery
== TELNET_DO
) {
573 * Build sub-negotiation packet (RFC 855).
575 * @param option telnet option
576 * @param response output buffer of response bytes
577 * @throws IOException if an I/O error occurs
579 private void telnetSendSubnegResponse(final int option
,
580 final byte [] response
) throws IOException
{
582 byte [] buffer
= new byte[response
.length
+ 5];
583 buffer
[0] = (byte)TELNET_IAC
;
584 buffer
[1] = (byte)TELNET_SB
;
585 buffer
[2] = (byte)option
;
586 System
.arraycopy(response
, 0, buffer
, 3, response
.length
);
587 buffer
[response
.length
+ 3] = (byte)TELNET_IAC
;
588 buffer
[response
.length
+ 4] = (byte)TELNET_SE
;
589 output
.rawWrite(buffer
);
593 * Telnet option: Terminal Speed (RFC 1079). Client side.
595 * @throws IOException if an I/O error occurs
597 private void telnetSendTerminalSpeed() throws IOException
{
598 byte [] response
= {0, '3', '8', '4', '0', '0', ',',
599 '3', '8', '4', '0', '0'};
600 telnetSendSubnegResponse(32, response
);
604 * Telnet option: Terminal Type (RFC 1091). Client side.
606 * @throws IOException if an I/O error occurs
608 private void telnetSendTerminalType() throws IOException
{
609 byte [] response
= {0, 'v', 't', '1', '0', '0' };
610 telnetSendSubnegResponse(24, response
);
614 * Telnet option: Terminal Type (RFC 1091). Server side.
616 * @throws IOException if an I/O error occurs
618 private void requestTerminalType() throws IOException
{
619 byte [] response
= new byte[1];
621 telnetSendSubnegResponse(24, response
);
625 * Telnet option: Terminal Speed (RFC 1079). Server side.
627 * @throws IOException if an I/O error occurs
629 private void requestTerminalSpeed() throws IOException
{
630 byte [] response
= new byte[1];
632 telnetSendSubnegResponse(32, response
);
636 * Telnet option: New Environment (RFC 1572). Server side.
638 * @throws IOException if an I/O error occurs
640 private void requestEnvironment() throws IOException
{
641 byte [] response
= new byte[1];
643 telnetSendSubnegResponse(39, response
);
647 * Send the options we want to negotiate on.
649 * <p>The options we use are:
653 * Binary Transmission RFC 856
654 * Suppress Go Ahead RFC 858
655 * Negotiate About Window Size RFC 1073
656 * Terminal Type RFC 1091
657 * Terminal Speed RFC 1079
658 * New Environment RFC 1572
660 * When run as a server:
664 * @throws IOException if an I/O error occurs
666 void telnetSendOptions() throws IOException
{
667 if (master
.binaryMode
== false) {
668 // Binary Transmission: must ask both do and will
673 if (master
.goAhead
== true) {
679 // Server only options
680 if (master
.isServer
== true) {
681 // Enable Echo - I echo to them, they do not echo back to me.
685 if (master
.doTermType
== true) {
686 // Terminal type - request it
690 if (master
.doTermSpeed
== true) {
691 // Terminal speed - request it
695 if (master
.doNAWS
== true) {
700 if (master
.doEnvironment
== true) {
701 // Environment - request it
707 if (master
.doTermType
== true) {
708 // Terminal type - request it
712 if (master
.doTermSpeed
== true) {
713 // Terminal speed - request it
717 if (master
.doNAWS
== true) {
722 if (master
.doEnvironment
== true) {
723 // Environment - request it
733 * New Environment parsing state.
735 private enum EnvState
{
743 * Handle the New Environment option. Note that this implementation
744 * fails to handle ESC as defined in RFC 1572.
746 private void handleNewEnvironment() {
747 Map
<String
, String
> newEnv
= new TreeMap
<String
, String
>();
749 EnvState state
= EnvState
.INIT
;
750 StringBuilder name
= new StringBuilder();
751 StringBuilder value
= new StringBuilder();
754 System.err.printf("handleNewEnvironment() %d bytes\n",
755 subnegBuffer.size());
758 for (int i
= 1; i
< subnegBuffer
.size(); i
++) {
759 Byte b
= subnegBuffer
.get(i
);
761 System.err.printf(" b: %c %d 0x%02x\n", (char)b.byteValue(),
770 state
= EnvState
.TYPE
;
772 // The other side isn't following the rules, see ya.
778 // Looking for "VAR" or "USERVAR"
781 state
= EnvState
.NAME
;
782 name
= new StringBuilder();
785 state
= EnvState
.NAME
;
786 name
= new StringBuilder();
788 // The other side isn't following the rules, see ya
794 // Looking for "VALUE" or a name byte
797 state
= EnvState
.VALUE
;
798 value
= new StringBuilder();
800 // Take it as an environment variable name/key byte
801 name
.append((char)b
.byteValue());
807 // Looking for "VAR", "USERVAR", or a name byte, or the end
810 state
= EnvState
.NAME
;
811 if (value
.length() > 0) {
813 System.err.printf("NAME: '%s' VALUE: '%s'\n",
816 newEnv
.put(name
.toString(), value
.toString());
818 name
= new StringBuilder();
821 state
= EnvState
.NAME
;
822 if (value
.length() > 0) {
824 System.err.printf("NAME: '%s' VALUE: '%s'\n",
827 newEnv
.put(name
.toString(), value
.toString());
829 name
= new StringBuilder();
831 // Take it as an environment variable value byte
832 value
.append((char)b
.byteValue());
837 throw new RuntimeException("Invalid state: " + state
);
842 if ((name
.length() > 0) && (value
.length() > 0)) {
844 System.err.printf("NAME: '%s' VALUE: '%s'\n", name, value);
846 newEnv
.put(name
.toString(), value
.toString());
849 for (String key
: newEnv
.keySet()) {
850 if (key
.equals("LANG")) {
851 language
= newEnv
.get(key
);
853 if (key
.equals("LOGNAME")) {
854 username
= newEnv
.get(key
);
856 if (key
.equals("USER")) {
857 username
= newEnv
.get(key
);
863 * Handle an option sub-negotiation.
865 * @throws IOException if an I/O error occurs
867 private void handleSubneg() throws IOException
{
870 // Sanity check: there must be at least 1 byte in subnegBuffer
871 if (subnegBuffer
.size() < 1) {
872 // Buffer too small: the other side is a broken telnetd, it did
873 // not send the right sub-negotiation data. Bail out now.
876 option
= subnegBuffer
.get(0);
882 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
883 // Server sent "SEND", we say "IS"
884 telnetSendTerminalType();
886 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
887 // Client sent "IS", record it
888 StringBuilder terminalString
= new StringBuilder();
889 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
890 terminalString
.append((char)subnegBuffer
.
893 master
.terminalType
= terminalString
.toString();
895 System.err.printf("terminal type: '%s'\n",
896 master.terminalType);
903 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
904 // Server sent "SEND", we say "IS"
905 telnetSendTerminalSpeed();
907 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
908 // Client sent "IS", record it
909 StringBuilder speedString
= new StringBuilder();
910 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
911 speedString
.append((char)subnegBuffer
.get(i
).byteValue());
913 master
.terminalSpeed
= speedString
.toString();
915 System.err.printf("terminal speed: '%s'\n",
916 master.terminalSpeed);
923 if (subnegBuffer
.size() >= 5) {
927 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
930 windowWidth
= subnegBuffer
.get(i
) * 256;
933 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
936 windowWidth
+= subnegBuffer
.get(i
);
939 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
942 windowHeight
= subnegBuffer
.get(i
) * 256;
945 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
948 windowHeight
+= subnegBuffer
.get(i
);
954 handleNewEnvironment();
964 * Reads up to len bytes of data from the input stream into an array of
967 * @param buf the buffer into which the data is read.
968 * @param off the start offset in array b at which the data is written.
969 * @param len the maximum number of bytes to read.
970 * @return the total number of bytes read into the buffer, or -1 if there
971 * is no more data because the end of the stream has been reached.
972 * @throws IOException if an I/O error occurs
974 private int readImpl(final byte[] buf
, final int off
,
975 final int len
) throws IOException
{
979 // The current writing position in buf.
982 // We will keep trying to read() until we have something to return.
985 // Read up to len bytes
986 byte [] buffer
= new byte[len
];
989 // Read some data from the other end
990 int rc
= input
.read(buffer
);
992 // Check for EOF or error
997 // EOF, just return it.
1001 // Loop through the read bytes
1002 for (int i
= 0; i
< bufferN
; i
++) {
1005 if (subnegEnd
== true) {
1006 // Looking for IAC SE to end this subnegotiation
1007 if (b
== (byte)TELNET_SE
) {
1013 } else if (b
== (byte)TELNET_IAC
) {
1015 // An argument to the subnegotiation option
1016 subnegBuffer
.add((byte)TELNET_IAC
);
1021 // An argument to the subnegotiation option
1022 subnegBuffer
.add(b
);
1027 // Look for DO/DON'T/WILL/WON'T option
1028 if (dowill
== true) {
1034 // Binary Transmission
1035 if (dowillType
== (byte)TELNET_WILL
) {
1036 // Server will use binary transmission, yay.
1037 master
.binaryMode
= true;
1038 } else if (dowillType
== (byte)TELNET_DO
) {
1039 // Server asks for binary transmission.
1041 master
.binaryMode
= true;
1042 } else if (dowillType
== (byte)TELNET_WONT
) {
1043 // We're screwed, server won't do binary
1045 master
.binaryMode
= false;
1047 // Server demands NVT ASCII mode.
1048 master
.binaryMode
= false;
1054 if (dowillType
== (byte)TELNET_WILL
) {
1055 // Server will use echo, yay.
1056 master
.echoMode
= true;
1057 } else if (dowillType
== (byte)TELNET_DO
) {
1058 // Server asks for echo.
1060 master
.echoMode
= true;
1061 } else if (dowillType
== (byte)TELNET_WONT
) {
1062 // We're screwed, server won't do echo.
1063 master
.echoMode
= false;
1065 // Server demands no echo.
1066 master
.echoMode
= false;
1071 // Suppress Go Ahead
1072 if (dowillType
== (byte)TELNET_WILL
) {
1073 // Server will use suppress go-ahead, yay.
1074 master
.goAhead
= false;
1075 } else if (dowillType
== (byte)TELNET_DO
) {
1076 // Server asks for suppress go-ahead.
1078 master
.goAhead
= false;
1079 } else if (dowillType
== (byte)TELNET_WONT
) {
1080 // We're screwed, server won't do suppress
1082 master
.goAhead
= true;
1084 // Server demands Go-Ahead mode.
1085 master
.goAhead
= true;
1090 // Terminal Type - send what's in TERM
1091 if (dowillType
== (byte)TELNET_WILL
) {
1092 // Server will use terminal type, yay.
1094 && master
.doTermType
1096 requestTerminalType();
1097 master
.doTermType
= false;
1098 } else if (!master
.isServer
) {
1099 master
.doTermType
= true;
1101 } else if (dowillType
== (byte)TELNET_DO
) {
1102 // Server asks for terminal type.
1104 master
.doTermType
= true;
1105 } else if (dowillType
== (byte)TELNET_WONT
) {
1106 // We're screwed, server won't do terminal type.
1107 master
.doTermType
= false;
1109 // Server will not listen to terminal type.
1110 master
.doTermType
= false;
1116 if (dowillType
== (byte)TELNET_WILL
) {
1117 // Server will use NAWS, yay.
1118 master
.doNAWS
= true;
1119 // NAWS cannot be requested by the server, it is
1120 // only sent by the client.
1121 } else if (dowillType
== (byte)TELNET_DO
) {
1122 // Server asks for NAWS.
1124 master
.doNAWS
= true;
1125 } else if (dowillType
== (byte)TELNET_WONT
) {
1126 // Server won't do NAWS.
1127 master
.doNAWS
= false;
1129 // Server will not listen to NAWS.
1130 master
.doNAWS
= false;
1136 if (dowillType
== (byte)TELNET_WILL
) {
1137 // Server will use terminal speed, yay.
1139 && master
.doTermSpeed
1141 requestTerminalSpeed();
1142 master
.doTermSpeed
= false;
1143 } else if (!master
.isServer
) {
1144 master
.doTermSpeed
= true;
1146 } else if (dowillType
== (byte)TELNET_DO
) {
1147 // Server asks for terminal speed.
1149 master
.doTermSpeed
= true;
1150 } else if (dowillType
== (byte)TELNET_WONT
) {
1151 // We're screwed, server won't do terminal speed.
1152 master
.doTermSpeed
= false;
1154 // Server will not listen to terminal speed.
1155 master
.doTermSpeed
= false;
1161 if (dowillType
== (byte)TELNET_WILL
) {
1162 // Server will use NewEnvironment, yay.
1164 && master
.doEnvironment
1166 requestEnvironment();
1167 master
.doEnvironment
= false;
1168 } else if (!master
.isServer
) {
1169 master
.doEnvironment
= true;
1171 } else if (dowillType
== (byte)TELNET_DO
) {
1172 // Server asks for NewEnvironment.
1174 master
.doEnvironment
= true;
1175 } else if (dowillType
== (byte)TELNET_WONT
) {
1176 // Server won't do NewEnvironment.
1177 master
.doEnvironment
= false;
1179 // Server will not listen to New Environment.
1180 master
.doEnvironment
= false;
1186 // Other side asked for something we don't
1187 // understand. Tell them we will not do this option.
1188 refuse(dowillType
, b
);
1194 } // if (dowill == true)
1196 // Perform read processing
1197 if (b
== (byte)TELNET_IAC
) {
1202 buf
[bufN
++] = (byte)TELNET_IAC
;
1213 case (byte)TELNET_SE
:
1214 // log.debug1(" END Sub-Negotiation");
1216 case (byte)TELNET_NOP
:
1217 // log.debug1(" NOP");
1219 case (byte)TELNET_DM
:
1220 // log.debug1(" Data Mark");
1222 case (byte)TELNET_BRK
:
1223 // log.debug1(" Break");
1225 case (byte)TELNET_IP
:
1226 // log.debug1(" Interrupt Process");
1228 case (byte)TELNET_AO
:
1229 // log.debug1(" Abort Output");
1231 case (byte)TELNET_AYT
:
1232 // log.debug1(" Are You There?");
1234 case (byte)TELNET_EC
:
1235 // log.debug1(" Erase Character");
1237 case (byte)TELNET_EL
:
1238 // log.debug1(" Erase Line");
1240 case (byte)TELNET_GA
:
1241 // log.debug1(" Go Ahead");
1243 case (byte)TELNET_SB
:
1244 // log.debug1(" START Sub-Negotiation");
1245 // From here we wait for the IAC SE
1247 subnegBuffer
.clear();
1249 case (byte)TELNET_WILL
:
1250 // log.debug1(" WILL");
1254 case (byte)TELNET_WONT
:
1255 // log.debug1(" WON'T");
1259 case (byte)TELNET_DO
:
1260 // log.debug1(" DO");
1264 if (master
.binaryMode
== true) {
1265 // log.debug1("Telnet DO in binary mode");
1269 case (byte)TELNET_DONT
:
1270 // log.debug1(" DON'T");
1275 // This should be equivalent to IAC NOP
1276 // log.debug1("Will treat as IAC NOP");
1282 } // if (iac == true)
1285 * All of the regular IAC processing is completed at this
1286 * point. Now we need to handle the CR and CR LF cases.
1288 * According to RFC 854, in NVT ASCII mode:
1293 if (master
.binaryMode
== false) {
1296 if (readCR
== true) {
1297 // This is CR LF. Send CR LF and turn the cr
1304 // This is bare LF. Send LF.
1310 if (readCR
== true) {
1311 // This is CR NUL. Send CR and turn the cr
1317 // This is bare NUL. Send NUL.
1318 buf
[bufN
++] = C_NUL
;
1323 if (readCR
== true) {
1324 // This is CR CR. Send a CR NUL and leave
1327 buf
[bufN
++] = C_NUL
;
1330 // This is the first CR. Set the cr flag.
1335 if (readCR
== true) {
1336 // This was a bare CR in the stream.
1341 // This is a regular character. Pass it on.
1347 * This is the case for any of:
1349 * 1) A NVT ASCII character that isn't CR, LF, or
1352 * 2) A NVT binary character.
1354 * For all of these cases, we just pass the character on.
1358 } // if (b == TELNET_IAC)
1360 } // for (int i = 0; i < bufferN; i++)
1362 } while (bufN
== 0);
1364 // Return bytes read